פורסם: 27 במרץ 2026
מעברים בין תצוגות בהיקף רכיב מאפשרים להריץ כמה מעברים בין תצוגות בו-זמנית, להטמיע מעברים בין תצוגות בתוך מעברים אחרים ולפתור בעיות שעלולות להתרחש במעברים בין תצוגות בהיקף מסמך – וכל זה תוך שמירה על האינטראקטיביות של שאר הדף.z-index במדריך הזה מוסבר איך משתמשים בהם.
הצורך במעברים בין תצוגות עם היקף צר יותר
כשמתחילים מעבר תצוגה באותו מסמך באמצעות document.startViewTransition() (או באמצעות הגרסה המקבילה שלו במסמך אחר), הדפדפן מגדיר את מעבר התצוגה שמתקבל בהיקף המסמך.
אחרי שהקריאה החוזרת לעדכון מופעלת והדפדפן מצלם את כל הרכיבים הנדרשים, שכבת העל ::view-transition והעץ של רכיבי פסאודו שנוצרים ממנה מצורפים לרכיב :root, html בדוגמה הבאה.
html
├─ ::view-transition
│ └─ ::view-transition-group(root)
│ └─ ::view-transition-image-pair(root)
│ ├─ ::view-transition-old(root)
│ └─ ::view-transition-new(root)
├─ head
└─ body
└─ …
מכיוון שהשכבה ::view-transition מוצגת מעל רכיב השורש של המעבר, זה עלול להוביל למצבים לא צפויים. לדוגמה, יכול להיות שאלמנטים שמשתתפים במעבר בין תצוגות יחפפו פתאום אלמנטים אחרים שלא משתתפים, או שאלמנטים לא ייחתכו יותר על ידי רכיב העוטף שלהם במהלך המעבר בין התצוגות.
הדגמה חיה
הקלטת הדגמה
הפעלה מחדש של pointer-events ב-::view-transition או שימוש בקבוצות מעבר תצוגה מקוננות יכולים לפתור חלק מתופעות הלוואי שמעברי תצוגה בהיקף מסמך יוצרים. עם זאת, השיטות האלה לא יכולות לפתור את כל הבעיות.
לדוגמה, אלמנטים עם position: fixed או חלונות קופצים עדיין מוסתרים על ידי מעבר תצוגה בהיקף המסמך בזמן שהמעבר פעיל – מצב שנקרא גם בעיית z-index.
בסרטון ההדגמה הבא, מעבירים את המתג של חלון הקופץ למצב פעיל ואז לוחצים על הלחצן ערבוב כדי להתחיל מעבר תצוגה בהיקף המסמך. קבוצות מעברים בתצוגה מקוננת פותרות את בעיית החיתוך, אבל בעיית השכבות נשארת.
הדגמה חיה
הקלטת הדגמה
פתרון עקיף אחד הוא ללכוד את popover כחלק ממעבר התצוגה על ידי הקצאת view-transition-name. השיטה הזו יכולה לעבוד עבור מופע יחיד, אבל היא מסורבלת לתחזוקה ומעמיסה על תהליך יצירת התמונות.
מעברי תצוגה בהיקף של רכיב
מעברים בין תצוגות בהיקף של רכיב מאפשרים להתחיל מעבר בין תצוגות בעץ משנה של ה-DOM. במקום להתקשר אל document.startViewTransition(), מתקשרים אל element.startViewTransition() ברכיב שרירותי, וכך מגדירים את היקף המעבר בין התצוגות לרכיב הזה.
בקטע הקוד הבא, הדפדפן מתחיל מעבר תצוגה בהיקף רכיב ברכיב <ul>.
document.querySelector('ul').startViewTransition({
callback: () => {
// … code that manipulates the contents of <ul>
},
})
האלמנט שבו מפעילים את element.startViewTransition() – לדוגמה, <ul> – נקרא שורש המעבר או ההיקף.
כשדפדפן מצמצם את היקף המעבר בין תצוגות לרכיב מסוים, הוא מבודד אותו משאר ה-DOM:
- הדפדפן מחפש רכיבים לצילום תמונת מצב רק בעץ המשנה של ההיקף.
- במהלך תהליך יצירת התמונה – בזמן ההפעלה של הקריאה החוזרת
update– רק העיבוד של ההיקף נעצר. - עץ פסאודו
::view-transitionשנוצר מוזרק לשורש המעבר.
לדוגמה, עם <ul>, עץ ה-DOM נראה כך בזמן שהנפשת המעבר פעילה:
html
├─ head
└─ body
├─ ul
│ ├─ ::view-transition
│ │ └─ ::view-transition-group(root)
│ │ ├─ ::view-transition-group-children(root)
│ │ │ └─ …
│ │ └─ ::view-transition-image-pair(root)
│ │ ├─ ::view-transition-old(root)
│ │ └─ ::view-transition-new(root)
│ ├─ li
│ ├─ li
│ └─ li
├─ button#showpopover
├─ button#reorder
└─ div#popover
└─ p
האלמנט ::view-transition pseudo הוא באותו גודל ובאותה צורה כמו רכיב השורש של המעבר, והוא מוצג רק מעל רכיב השורש של המעבר. לכן, סדר השכבות של רכיבים מחוץ לשורש המעבר נשמר.
לדוגמה, אם יש לכם חלון קופץ שמוצג מעל רכיב <ul> ואז אתם מתחילים מעבר תצוגה בהיקף רכיב ברכיב <ul>, החלון הקופץ לא מוסתר על ידי העץ הפסאודו של מעבר התצוגה.
אפשר לנסות את זה בהדגמה הבאה. יש לו שני כפתורים. הלחצן הראשון מחליף את מצב החלון הקופץ, והלחצן השני מסדר מחדש את הפריטים ברשימה באמצעות מעבר תצוגה בהיקף של רכיב.
הדגמה חיה
הקלטת הדגמה
בגלל שנעשה שימוש במעברים בין תצוגות בהיקף של רכיב, חלון הקופץ נשאר גלוי מעל הרכיב <ul> בזמן שהמעבר פעיל.
בנוסף, הרכיבים שמחוץ לרכיב <ul>, כמו הכפתורים, נשארים אינטראקטיביים כי הם לא חלק מההיקף.
היקפים עם השתתפות עצמית וקבוצות מקוננות של מעברי תצוגה
כשמתחילים מעבר תצוגה עם היקף של רכיב ברכיב שחלקים ממנו חורגים מהגבולות (כלומר, כשמאפיין overflow שלו מוגדר ל-hidden, ל-scroll או ל-clip), אפשר לראות שהתוכן של מעבר התצוגה נשאר חתוך.
הסיבה לכך היא שמעברים בין תצוגות בהיקף של רכיב מטפלים באופן אוטומטי בפעולות הבאות:
- ההיקף מוחל באופן אוטומטי, ולכן הוא משתתף בעצמו.
view-transition-name: root - ההיקף מוחל באופן אוטומטי על
view-transition-group: containכדי להפעיל קבוצות מקוננות של מעברי תצוגה. - אם שורש ההיקף חותך את הגלישה שלו,
::view-transition-group-children(root)פסאודו שנוצר חותך באופן אוטומטי את התוכן שלו באמצעותoverflow: clip, וכך מונע את הגלישה של הפסאודו מחוץ לשורש המעבר.
כתוצאה מכך, תוכלו להשתמש ב-CSS רק ברכיבים שאתם רוצים לכלול במעברי התצוגה. לדוגמה, בהדגמה של הרשימה, ה-CSS מוסיף רק שמות לפריטים ברשימה:
ul li {
view-transition-name: match-element;
view-transition-class: album;
}
אפשר לנסות את זה בהדגמה הבאה. הוא מאפשר לכם לשנות את ההגדרה של השתתפות עצמית. כשההיקף הוא self-participating (ברירת המחדל), הכול פועל כצפוי. אם ההיקף לא משתתף בעצמו, הגבול שלו משתנה מיד והתוכן שלו יוצא מהעטיפה במהלך המעבר.
הדגמה חיה
הקלטת הדגמה
לצורך השוואה, הנה מבנה פסאודו-העץ של ההדגמה הזו עם השתתפות עצמית:
html
├─ head
└─ body
├─ ul
│ ├─ ::view-transition
│ │ └─ ::view-transition-group(root)
│ │ ├─ ::view-transition-group-children(root)
│ │ │ ├─ ::view-transition-group(item1)
│ │ │ │ └─ ::view-transition-image-pair(item1)
│ │ │ │ ├─ ::view-transition-old(item1)
│ │ │ │ └─ ::view-transition-new(item1)
│ │ │ ├─ ::view-transition-group(item2)
│ │ │ │ └─ …
│ │ │ …
│ │ └─ ::view-transition-image-pair(root)
│ │ ├─ ::view-transition-old(root)
│ │ └─ ::view-transition-new(root)
│ ├─ li
│ ├─ li
│ └─ li
└─ button#reorder
מכיוון שרכיב השורש של המעבר, <ul>, חותך את התוכן שלו בצורה אנכית, גם הרכיב ::view-transition-group-children(root) חותך את התוכן באופן אוטומטי.
מעברים בין תצוגות בהיקף של רכיב
מעברי תצוגה עם היקף ברמת האלמנט פועלים בבידוד, ולכן אפשר להפעיל כמה מעברי תצוגה עם היקף ברמת האלמנט בו-זמנית אם יש להם היקף שונה.
בהדגמה הבאה יש שני לחצני סידור מחדש, אחד לכל רשימה. כל לחצן מתחיל מעבר תצוגה בהיקף רכיב רק ברשימה המתאימה. מכיוון שעצי ה-DOM של שתי הרשימות לא חופפים, שני מעברי התצוגה בהיקף של רכיב יכולים לפעול בו-זמנית בבידוד.
הדגמה חיה
הקלטת הדגמה
הבידוד הזה מאפשר גם לעשות שימוש חוזר בערכי view-transition-name בהיקפים שונים. כל עוד השם ייחודי בהיקף שלו, לא תהיה התנגשות.
מעברים בין תצוגות בהיקף של רכיב מקונן והכללה של view-transition-name
כשעצי ה-DOM של כמה מעברי תצוגה בהיקף רכיב חופפים, יש סיכון של התנגשות ערכים של view-transition-name. לכן, הדפדפן מקצה אוטומטית את הערך view-transition-scope: all למעברי תצוגה פעילים בהיקף של רכיב, כדי לצמצם את הסיכון הזה.
בדומה לאופן שבו anchor-scope מגדיר את היקף הערכים של anchor-name, המאפיין view-transition-scope מבטיח שהיקף הערכים של view-transition-name יוגדר לעץ המשנה של האלמנט. המאפיין מקבל את הערך none, רשימה של שמות שרוצים להגדיר להם היקף, או all כדי להגדיר היקף לכל הערכים.
בנוסף למניעת חשיפה של שמות, view-transition-scope מונע גם את הלכידה של רכיב והתוכן שלו על ידי מעבר תצוגה חיצוני ובו-זמני. במהלך תהליך יצירת תמונת המצב, כשהמערכת עוברת על עץ המשנה כדי למצוא רכיב ליצירת תמונת מצב, היא מתעלמת מרכיבים (ומעץ המשנה כולו שלהם) שהוחל עליהם view-transition-scope: all. ההנחה היא שהרכיבים האלה כבר משתתפים במעבר תצוגה אחר בהיקף רכיב.
ההדגמה הבאה היא וריאציה של ההדגמה הקודמת. בנוסף לשני הלחצנים שמערבבים את תוכן הרשימה, יש גם לחצן החלפה להחלפת הרשימות. החלפה מתבצעת על ידי מעבר בין .reversed כיתות ב-#lists-wrapper.
הדגמה חיה
הקלטת הדגמה
מכיוון שהאפקט view-transition-scope: all מופעל אוטומטית במהלך מעבר ההחלפה, אפשר להתחיל מעבר החלפה חיצוני מקביל בזמן שמעבר ההחלפה עדיין מתבצע.
בנוסף, view-transition-scope: all מונע גם את צילום התמונה של רכיב במעבר חיצוני, ולכן בהדגמה נוספים גם ערכי view-transition-name לרכיבי ה-Wrapping של רכיבי <ul>.
#list1-wrapper, #list2-wrapper {
view-transition-name: attr(id type(<custom-ident>));
}
אחרי שמתחילים לערבב את הרשימה השנייה ואז מחליפים בין שתי הרשימות, עץ הפסאודו של ההדגמה הזו נראה כך:
html
├─ head
└─ body
└─ #lists-wrapper.reversed (SCOPE)
├─ ::view-transition
│ └─ ::view-transition-group(lists-wrapper)
│ ├─ ::view-transition-group-children(lists-wrapper)
│ │ ├─ ::view-transition-group(list1-wrapper)
│ │ │ └─ ::view-transition-image-pair(list1-wrapper)
│ │ │ ├─ ::view-transition-old(list1-wrapper)
│ │ │ └─ ::view-transition-new(list1-wrapper)
│ │ └─ ::view-transition-group(list2-wrapper)
│ │ └─ ::view-transition-image-pair(list2-wrapper)
│ │ ├─ ::view-transition-old(list2-wrapper)
│ │ └─ ::view-transition-new(list2-wrapper)
│ └─ ::view-transition-image-pair(lists-wrapper)
│ ├─ ::view-transition-old(lists-wrapper)
│ └─ ::view-transition-new(lists-wrapper)
├─ div#list1-wrapper
│ ├─ ul
│ │ ├─ li#item1
│ │ ├─ li#item2
│ │ └─ li#item3
│ └─ button.reorder
└─ div#list2-wrapper
├─ ul (SCOPE)
│ ├─ ::view-transition
│ │ └─ ::view-transition-group(list)
│ │ ├─ ::view-transition-group-children(list )
│ │ │ ├─ ::view-transition-group(item4)
│ │ │ │ └─ ::view-transition-image-pair(item4)
│ │ │ │ ├─ ::view-transition-old(item4)
│ │ │ │ └─ ::view-transition-new(item4)
│ │ │ ├─ ::view-transition-group(item5)
│ │ │ │ └─ …
│ │ │ …
│ │ └─ ::view-transition-image-pair(list)
│ │ ├─ ::view-transition-old(list)
│ │ └─ ::view-transition-new(list)
│ ├─ li#item4
│ ├─ li#item5
│ └─ li#item6
└─ button.reorder
מידע נוסף
מידע נוסף על מעברים בין תצוגות בהיקף של רכיב זמין במאמר ההסבר, במפרט css-view-transitions-2 וברשימת העריכות הפתוחות במפרט.