למרות אין סוף פוסטים שנכתבו בנושא, ולא משנה כמה קראתי וכמה הבנתי (או אולי לא הבנתי לגמרי…), תמיד תהיה הפעם הזאת שלא אבין למה לעזאזל אלמנט אחד עולה מעל אלמנט אחר. אני בטוחה שאני לא היחידה שעדיין נתקלת בסיטואציה הזאת, וכמו לדבג css בעזרת הצבע red, אין אחד או אחת שלא שינתה את הערך של z-index
ל-9999 רק כדי לקוות בסתר הלב שעוד 9 יפתור את הבעיה 😉
אני חייבת להתוודות שאפילו תוך כדי כתיבת הפוסט, בדיקת הקוד טרם כתיבתו ואחרי שכתבתי עליו, היו פעמים שחשבתי שהבנתי מה קורה ושוב הופתעתי לגלות התנהגות שלא צפיתי.
מסכמת את ההבנות שלי כשחקרתי מה קורה ואיך הכל עובד, מקווה קצת לפשט את הנושא, ולהביא כמה מקורות קריאה מעולים (בסוף הפוסט) שיסבירו, יבהירו ואולי אחת ולתמיד יעשו סדר בכל הנושא של z-index
.
שכבות (וציר ה-z)
בפוטושופ, אחד הדברים הראשונים שלומדים להבין ולהעריך הוא עבודה עם שכבות. ככל שיש יותר – ככה יהיה קל יותר לשנות ולשפר את הקובץ. השכבות נערמות אחת על השניה, ואם יש תוכן חופף, השכבה העליונה ביותר תהיה זאת שתוצג. ניתן לאגד שכבות בקבוצות ואפשר בקלות לשנות את סדר השכבות, וקל ופשוט לראות את זה בחלונית השכבות של הפוטושופ.
בדפדפן ההתנהגות די דומה, אבל יחד עם זאת ממש לא. בדפדפן, אלמנטים יכולים לזוז על ציר ה-x, על ציר ה-y ועל ציר ה-z, שהוא בעצם מעין ציר עומק (כמו ציר השכבות בפוטושופ).
אבל אם בפוטושופ גלוי וידוע לנו איזה שכבה באה מעל מי ואיך היא משפיעה על שכבות שהיא מעליהן, אזי ב-html אנחנו נראה את המבנה של ה״קבוצות״ של שכבות שלנו במבנה ה-html, אבל עד שלא נצלול פנימה, ונבין איך ה-css משפיע, לא נדע בוודאות מה הסדר של השכבות על פני ציר ה-z.
סדר ראשוני
סדר זה נקרא root stacking context או local stacking context. בברירת המחדל, אם נתייחס לדוגמה ל-div-ים הראשיים של הדפדפן, כל אחד מהם מופיע אחד אחרי השני, אבל ה-div השני גם יופיע גבוה יותר בהיררכה של ציר ה-z , השלישי יותר גבוה מהשני וכן הלאה.
בדוגמת הקוד הבאה אפשר לראות את האלמנטים בסדר ההופעה ה-html-לי שלהם – כל האלמנטים הם
display:
inline-block
ויש להם הגדרה שלmargin
שלילי ואפשר לראות את השכבות שהם יוצרים:
See the Pen Understanding z-index – 1 by Rachel Bratt Tannenbaum (@rachelbt) on CodePen.
שינוי סדר השכבות – stacking context
בתוך אותו הסדר, נוכל לשנות את סדר גובה השכבות, אפילו עוד לפני שנדבר על המאפיין z-index
. ברגע שנתנו לאחד ה-div-ים מאפיין שיש לו את היכולת לשנות את הסדר השכבות (stacking contex), הוא מקבל קדימות והוא עובר לשכבה גבוהה יותר. ומה הם המאפיינים האלה?
המאפיין position
, על כל הערכים שלו (למעט static
). בעיקרון, סה״כ הגיוני שאם נתנו לאלמנט הגדרה של position
, אנחנו רוצים לשלוט על המיקום שלו ביחס לעצמו או ביחס לאחרים. זאת אומרת שאם למשל יהיו לנו 4 אלמנטים, ונרצה שהאלמנט הראשון יהיה מעל השני – כל שנזדקק לתת לו הוא את אחד המאפיינים שייצרו stacking contex חדש והופ, בלי שום שימוש ב z-index
העלינו אותו למעלה.
מאפיינים נוספים שמשפיעים באותה צורה הם לא מעטים בכלל. חלקם נשמע הגיוני שישפיעו ככה:
transform
perspective
- אלמנט עם ערך של
z-index
שונה מauto
שאבא שלו בעל המאפייןdisplay:flex
- אלמנט עם ערך של
z-index
שונה מauto
שאבא שלו בעל המאפייןdisplay:grid
וחלקם פחות:
- אלמנט שנתנו לו ערך של
opacity
נמוך מ-1 - אלמנט שהוחל עליו
filter
- ועוד…
לרשימה המלאה של מאפיינים המשפיעים על layering context
בדוגמת הקוד הבאה, כל האלמנטים קיבלו את אותן ההגדרות כמו מקודם, למעט 2 שינויים – אלמנט מספר 1 קיבל הגדרה של
transform: translateX
ואלמנט 4 קיבל הגדרה שלopacity: 0.99
.
See the Pen Understanding z-index – 1 by Rachel Bratt Tannenbaum (@rachelbt) on CodePen.
המאפיינים האלה גרמו לאלמנטים לקבל stacking context חדש, והיות ולאלמנטים האחרים אין שום מאפיין מיוחד, אלמנטים מספר אחת וארבע עולים מעליהם.
תוצאה זהה הייתה מתקבלת אם היינו נותנים את אחד מהמאפיינים האחרים ברשימה (כמו למשל position:relative
).
אבל אם לכל האלמנטים הייתה הגדרה של שינוי stacking context, למשל אם לכולם הייתה הגדרה של
, אזי תוספת של position:relative
opacity
או transform
לא הייתה משפיעה על אלמנטים אחת וארבע היות וגם כל שאר האלמנטים כבר קיבלו מאפיין ששינה את ה-stacking context שלהם ושוב, כולם ״שווים״. במצב הזה, כדי להעלות את אחד מהאלמנטים שלנו על פני ציר ה-z, נזדקק למאפיין נוסף והוא הz-index
.
הוספת המאפיין z-index
לפני שנתחיל, חשוב לדעת שהמאפיין z-index
לא ישפיע על אלמנט אלא אם הוגדר לו גם position
(שוב, למעט static
).
נחזור לדוגמה הקודמת, ונוסיף לכל האלמנטים position: relative
. התוספת הזו תחזיר אותנו לנקודת המוצא שאיתה פתחנו – שתיים עולה על אחת, שלוש על שתיים וכך הלאה
אותה דוגמת קוד כמו הקודמת, רק שהוספתי לאלמנטים את המאפיין
position: relative
See the Pen Understanding z-index – 2 by Rachel Bratt Tannenbaum (@rachelbt) on CodePen.
הפעם, האלמנטים שהוספנו להם מאפיינים (אלמנט 1 ואלמנט 4) לא ישנו את מיקומם על פני ציר ה-z. זה מפני שלא משנה אם יש להם מספר רב יותר של מאפיינים שמשנים את ה-stacking context – אין פה כפל מבצעים וממש מספיק מאפיין אחד להוציא מהקונטקסט. רק האלמנט שיקבל את המאפיין z-index
(בנוסף למאפיין position
) יקבל קדימות על ציר ה-z, והאלמנט שיקבל את הערך המספרי הגבוה ביותר של z-index
יהיה העליון מבניהם.
בסוגריים אוסיף שאם כולם יקבלו את אותו ערך של z-index
עדיין נישאר עם אותה התוצאה.
בדוגמה הבאה כל האלמנטים מוגדרים עם
position: relative
, אבל רק לאלמנט 1, 3 ו-5 יש הגדרה שלz-index:1
. ש״מעלה״ אותם שכבה.
See the Pen Understanding z-index – 2 by Rachel Bratt Tannenbaum (@rachelbt) on CodePen.
stacking context וילדים
הוספתי לכל האלמנטים בדוגמה הקודמת אלמנט-בן שהוא tooltip, ורק לשם ההדגמה הוא מוצג תמיד. כדי למקם אותו נתתי לו position:absolute
, וכמובן האלמנט העוטף קיבל position:relative
. ה-tooltip שאבא שלו הוא האחרון שמופיע בסדר ה-html יהיה הגבוה ביותר גם על פני ציר ה-z.
בדוגמה הבאה כל האלמנטים מוגדרים עם
position: relative
, ולכולם אלמנט בן עםposition:absolute
See the Pen Understanding z-index – with tooltip by Rachel Bratt Tannenbaum (@rachelbt) on CodePen.
אם אחד מה-tooltip-ים יקבל z-index
עם ערך גבוה יותר מ-1, הוא יהיה גבוה משאר האלמנטים, אפילו אם בסדר ה-html-לי האבא שלו מופיע בהיררכיה נמוכה יותר. כלומר, אם למשל ניתן לאחד מאלמנטי האב שלנו את ההגדרה של z-index:2
, אז הבן שלו יופיע גבוה יותר משאר הבנים האחרים.
מה יקרה אבל אם אחר כך ניתן לאחד הבנים האחרים ערך גבוה יותר של z-index
? הוא יופיע גבוה יותר מאשר זה שהאבא שלו עם z-index:2
. לכאורה, ההגיון היה אומר שאם לאבא יש z-index
גבוה יותר, אזי גם הילדים שלו יהיו גבוהים יותר. אבל ברגע שהגדרנו גם לילדים position: absolute
, יצרנו להם stacking context חדש ולכן הם נכנסים לאותו חישוב מספרי שבו ערך גבוה יותר של z-index
מנצח.
אפשר גם אחרת: isolation
כדי להמנע ממצבים כאלה, של ״מלחמות״ z-index
(בהנחה כמובן שאנחנו שולטים בכל ה-css), יש דרך לשלוט בסיטואציה הנ״ל בעזרת ההגדרה של isolation: isolate;
.
מה אנחנו משיגים עם זה?
isolation
בעצם עושה מעין scoping לאלמנטים ומשאיר את ה z-index
בתוך האבא שלו בלי להשפיע על שאר האלמנטים בעמוד.
אנחנו כופים על האלמנט שלנו לייצר stacking context חדש (אפילו אם הוא מלכתחילה כבר יצר אחת. הרי כבר הגדרנו על האלמנט position:relative
). מה ש״מוריד״ את האלמנט שוב בהיררכיית השכבות, ושוב, לא משנה אם ניתן לילד שלו z-index של 9999 הוא עדיין יהיה ״נעול״ לסביבה שלו.
נחזור שוב לדוגמה שלנו של ה-tooltip. לכל האלמנטים מוגדר position:relative
, ולכל הילדים position:absolute;
. האלמנט האחרון שנרשם ב-html הוא הגבוה ביותר על ציר ה-z. אבל אם ניתן ל-tooltip של האלמנט הראשון (האדום) z-index:1
הוא יופיע מעל כל שאר האלמנטים וככה זה יראה:
אם נוסיף לאלמנט הראשון (האדום) את ההגדרה isolation: isolate;
נשנה את ה-stacking context, ונחזיר אותו ל״מקום״ הראשוני שלו בהיררכיה על פני ציר ה-z.
See the Pen Understanding z-index – isolated by Rachel Bratt Tannenbaum (@rachelbt) on CodePen.
יוצא דופן
שניה לפני שמסיימים, יוצאי דופן:
זוכרים שכתבתי שהמאפיין z-index
לא ישפיע אם לא נגדיר גם position
עליו? אז קבלו את יוצאי הדופן – ילדים של אלמנט עם dispaly:grid
או dispaly:flex
. מה שאומר שאם נוסיף לאחד הילדים של אבא עם display:flex
את הערך של z-index:1;
הוא יהיה מעל האחים שלו.
בדוגמה הבאה, כל המעטפת קיבלה הגדרה של
display: flex;
ולאף אחד מהילדים אין הגדרה שלposition
, מה שאומר שלכאורהz-index
לא אמור להשפיע. אבל הוא כן משפיע, כי האלמנטים הם ילדים שלflex
See the Pen Understanding z-index – 1 by Rachel Bratt Tannenbaum (@rachelbt) on CodePen.
מקורות מידע
- דברים שלא ידענו על z-index, פוסט של לאה מליקוטי שיבולים
- Understanding Z-Index in CSS של Ahmad Shadeed, הסבר מלווה באיורים חמודים ומבהירים 🙂
- The Z-Index CSS Property: A Comprehensive Look
- What No One Told You About Z-Index
- How to solve the Z-index issue Within 1 minute
- What The Heck, z-index??
- Z-Index And The CSS Stack: Which Element Displays First?
- Stacking Context
- MDN – The stacking context
- Understanding Layout Algorithms
- Creating Stacking Context With
isolate
- Managing CSS Z-Index In Large Projects
- הדמיה מעולה של z-index ו- stacking-context של רותם הורוביץ
- לא לגמרי קשור מאמר מעניין על בנייה של אפקט פארלקס ב-css. יש במאמר דמו שמסביר את האפקט ועל הדרך גם ממחיש את המשמעות של
z-index
. - כלים לבדיקת האלמנטים שיש להם את המאפיין
z-index
ומציאת המיקום שלהם על ציר ה-z בעמוד:- אקספלורר: https://docs.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/3d-view/
- סרטון מעולה שמסביר על כלי הבדיקה של אקספלורר: https://www.youtube.com/watch?v=LVb1Xzzd72w
- כרום: https://chrome.google.com/webstore/detail/visbug/cdockenadnadldjbbgcallicgledbeoc?hl=en
תוספות (07.2023)
בדפדפנים יש שכבה חדשה שנקראת top-layer שהיא העליונה מכולם, ובעצם פותרת את בעיית ה z-index לאלמנטים שצריכים להיות מוגבהים משאר התוכן כמו מודל או פופאפים. כשמשתמשים במתודה של showModal על אלמנט dialog הדיאלוג נפתח באופן אוטומטי ב top layer.
popover הוא attribute, חדש שמתחיל להכנס לדפדפנים שההוספה שלו תעביר את האלמנט ל top-layer. הפיצ׳ר הזה עדיין לא נתמך מספיק ויש לו עוד בעיות מיקום, אבל ללא ספק הכיוון מבטיח 🙂
Offset parent and stacking context: positioning elements in all three dimensions – פוסט של שעוזר מאוד להבין מה זה stacking context ואיך הוא מתנהג
אוף! עדיף ללמוד פיזיקה
🙂 🙂 🙂
כתוב מעולה ולפחות רוב הנקודות באמת נקלטו תודה!
תודה! שמחתי 🙂