תמיכה בשכבה העליונה בכלי הפיתוח ל-Chrome

Alina Varkki
Alina Varkki

לכלי הפיתוח ל-Chrome נוספה תמיכה ברכיבים של שכבות עליונות, כדי שלמפתחים יהיה קל יותר לנפות באגים בקוד שלהם שבעזרתו אפשר להשתמש ברכיבים של שכבות עליונות.

במאמר הזה נתאר מהם אלמנטים של שכבות מובילות, איך כלי הפיתוח עוזרים להציג באופן חזותי את התוכן בשכבה העליונה כדי להבין ולנפות באגים במבנה DOM שמכיל את רכיבי השכבה העליונה, ואיך מיושמת תמיכה בשכבה העליונה של כלי הפיתוח.

מהם האלמנטים של השכבה העליונה והשכבה העליונה?

מה בדיוק קורה באופן פנימי כשפותחים <dialog> כחלון מודאלי? 🤔

הוא מועבר בשכבה העליונה. התוכן בשכבה העליונה מוצג מעל כל שאר התוכן. לדוגמה, תיבת דו-שיח של חלון עזר צריכה להופיע מעל כל תוכן ה-DOM האחר, לכן הדפדפן מציג את הרכיב הזה באופן אוטומטי ב 'שכבה עליונה' במקום לאלץ את המחברים להילחם ידנית ב-z-index. רכיב בשכבה עליונה מופיע מעל אלמנט גם עם אינדקס z הגבוה ביותר.

אפשר לתאר את השכבה העליונה כ 'שכבת הערימה הגבוהה ביותר'. לכל מסמך משויך אזור תצוגה אחד, ולכן גם שכבה עליונה אחת. אלמנטים מרובים יכולים להופיע בו-זמנית בתוך השכבה העליונה. כשזה קורה, הן מוערמות זו על גבי זו, המילה האחרונה מעל. במילים אחרות, כל האלמנטים של השכבה העליונה ממוקמים במקבץ האחרון, יוצא ראשון (LIFO) בשכבה העליונה.

הרכיב <dialog> הוא לא האלמנט היחיד שהדפדפן מעבד בשכבה עליונה. בשלב זה, רכיבי השכבות העליונות הם: חלונות קופצים, תיבות דו-שיח ורכיבים במצב מסך מלא.

בודקים את ההטמעה של תיבת הדו-שיח הבאה:

<main>
  <button onclick="window.dialog.showModal();">Open Dialog</button>
</main>
<dialog id="dialog"></dialog>

הנה הדגמה עם כמה תיבות דו-שיח עם סגנונות שחלו על הרקע שלהן (רקעים כפי שמתואר בהמשך):

מהי תמונת רקע?

למרבה המזל, יש דרך להתאים אישית את התוכן שמתחת לרכיב השכבה העליונה.

לכל רכיב בשכבה העליונה יש פסאודו-רכיב של CSS שנקרא רקע.

Backdrop הוא תיבה בגודל של אזור התצוגה שמעובדת ישירות מתחת לרכיב כלשהו בשכבה העליונה. פסאודו-רכיב ::backdrop מאפשר לטשטש, לעצב או להסתיר לגמרי כל דבר שנמצא מתחת לאלמנט, כשהוא נמצא ברמה העליונה בשכבה העליונה.

כשיוצרים מספר רכיבים חלון, הדפדפן מצייר את הרקע ישירות מתחת לרכיב הקדמי ביותר, ומעל לרכיבים אחרים במסך מלא.

כך מעצבים תמונת רקע:

/* The browser displays the backdrop only when the dialog.showModal() function opens the dialog.*/
dialog::backdrop {
    background: rgba(255,0,0,.25);
}

כיצד להציג רק את הרקע הראשון?

לכל רכיב בשכבה העליונה יש תמונת רקע ששייכת למקבץ שכבות למעלה. תמונות הרקע האלה נועדו לחפוף זו אל זו, כך שאם השקיפות של הרקע אינה 100%, ניתן לראות את הרקע שמתחתיו.

אם רק הרקע הראשון במקבץ של השכבות העליונות צריך להיות גלוי, אפשר לעשות זאת על ידי מעקב אחרי מזהי הפריטים במקבץ השכבות העליונות.

אם הרכיב שנוסף הוא לא הראשון בשכבה העליונה, הפונקציה שנקראת כאשר מציבים את הרכיב בשכבה העליונה מחילה מחלקה hiddenBackdrop על ::backdrop. המחלקה הזו מסירה כאשר הרכיב מוסר מהשכבה העליונה.

אפשר לראות את הקוד בהדגמה לדוגמה הזו:

עיצוב התמיכה בשכבה העליונה בכלי הפיתוח

תמיכה בכלי הפיתוח בשכבה העליונה עוזרת למפתחים להבין את הקונספט של השכבה העליונה ולהמחיש באופן חזותי את השינוי בתוכן של השכבה העליונה. התכונות האלה עוזרות למפתחים לזהות את הפרטים הבאים:

  • הרכיבים בשכבה העליונה בכל זמן והסדר שלהם.
  • הרכיב שמופיע בראש המקבץ בכל שלב.

בנוסף, תמיכה בשכבה העליונה של כלי הפיתוח עוזרת להמחיש את המיקום של פסאודו-רכיב של הרקע במקבץ השכבות העליונות. למרות שהשכבה העליונה לא רכיבה בעץ, היא ממלאת תפקיד חשוב באופן הפעולה שלה ויכולה להיות שימושית למפתחים.

בעזרת תכונות התמיכה בשכבה העליונה אפשר:

  1. תמיד אפשר לבדוק אילו אלמנטים נמצאים במקבץ של השכבות העליונות. מקבץ הייצוגים של השכבה העליונה משתנה באופן דינמי כשמוסיפים רכיבים או מסירים אותם מהשכבה העליונה.
  2. אפשר לראות את מיקום הרכיב בערימת השכבות העליונות.
  3. מדלגים מהאלמנט של השכבה העליונה או מהפסאודו-רכיב של הרקע בעץ אל הרכיב או מפסאודו-רכיב של הרקע במאגר של השכבה העליונה לייצוג, ובחזרה.

בואו נראה איך להשתמש בתכונות האלה.

מאגר השכבה העליונה

כדי להמחיש את הרכיבים של השכבה העליונה, כלי הפיתוח מוסיף מאגר של שכבה עליונה לעץ הרכיבים. הוא נמצא אחרי תג </html> הסוגר.

מאגר השכבות הזה מאפשר לכם לראות בכל שלב את הרכיבים במקבץ של השכבות העליונות. מאגר השכבה העליונה הוא רשימת קישורים לאלמנטים של השכבה העליונה ולרקעים שלהם. מקבץ הייצוגים של השכבה העליונה משתנה באופן דינמי כשמוסיפים רכיבים או מסירים אותם מהשכבה העליונה.

כדי למצוא את הרכיבים של השכבה העליונה בעץ הרכיבים או במאגר של השכבה העליונה, לוחצים על הקישורים מייצוג הרכיב בשכבה העליונה במאגר של השכבה העליונה לאותו רכיב בעץ הרכיבים ובחזרה.

כדי לדלג מרכיב מאגר השכבה העליון אל רכיב העץ של השכבה העליונה, לוחצים על הלחצן הצגה לצד הרכיב במאגר של השכבה העליונה.

מעבר מהקישור למאגר בשכבה העליונה אל הרכיב.

כדי לדלג מרכיב העץ בשכבה העליונה אל הקישור במאגר של השכבה העליונה, לוחצים על התג שכבה עליונה שלצד הרכיב.

מעבר מרכיב בקישור למאגר בשכבה העליונה.

אפשר להשבית כל תג, כולל התג השכבה העליונה. כדי להשבית את התגים, לוחצים לחיצה ימנית על תג כלשהו, בוחרים באפשרות הגדרות תגים ומבטלים את הסימון של התיבות לצד התגים שרוצים להסתיר.

השבתת התג.

סדר הרכיבים במקבץ השכבות העליונות

מאגר השכבה העליונה מציג את הרכיבים כפי שהם מופיעים במקבץ, אבל בסדר הפוך. החלק העליון של רכיב הערימה הוא האחרון ברשימת הרכיבים של מאגר השכבה העליונה. משמעות הדבר היא שהאלמנט האחרון ברשימת הגורמים המכילים בשכבה העליונה הוא האלמנט שאיתו אפשר לבצע פעולות כרגע במסמך.

התגים שליד רכיבי העץ מציינים אם הרכיבים שייכים לשכבה העליונה ומכילים את מספר המיקום של רכיב במקבץ.

בצילום המסך הזה, מקבץ השכבה העליונה מורכב משני אלמנטים, כשהרכיב השני נמצא בראש המקבץ. אם מסירים את הרכיב השני, הרכיב הראשון עובר לראש הרשימה.

סדר הרכיבים במקבץ.

קולאז'ים של תמונות רקע במאגר של השכבה העליונה

כפי שצוין למעלה, לכל רכיב בשכבה העליונה יש פסאודו-רכיב של CSS שנקרא 'רקע'. אפשר לעצב את הרכיב הזה, כך שכדאי גם לבדוק אותו ולראות את הייצוג שלו.

בעץ הרכיבים, רכיב של רקע נמצא לפני התג הסוגר של הרכיב שאליו הוא שייך. עם זאת, במאגר של השכבה העליונה מופיע קישור לרקע מעל לרכיב השכבה העליונה שאליו הוא שייך.

המיקום של מקבץ התמונות ברקע.

שינויים בעץ ה-DOM

ElementsTreeElement, המחלקה שאחראית ליצירה ולניהול של רכיבי עץ DOM בודדים בכלי הפיתוח, לא הספיקה כדי להטמיע מאגר שכבה עליונה.

כדי להציג את מאגר השכבה העליון כצומת בעץ, הוספנו מחלקה חדשה שיוצרת צמתים של רכיבי עץ של כלי פיתוח. בעבר, המחלקה שאחראית ליצירת עץ רכיבי DevTools אותחלה כל TreeElement עם DOMNode, שהיא מחלקה עם backendNodeId ומאפיינים אחרים שקשורים לקצה עורפי. backendNodeId, בתורו, מוקצה בקצה העורפי.

צומת המאגר בשכבה העליונה, שכולל רשימת קישורים לאלמנטים בשכבה העליונה, הנדרש לפעול כצומת רגיל של רכיב עץ. עם זאת, הצומת הזה אינו צומת DOM 'אמיתי' והקצה העורפי לא צריך ליצור את צומת המאגר של השכבה העליונה.

כדי ליצור צומת בממשק קצה שמייצג את השכבה העליונה, הוספנו סוג חדש של צומת של ממשק קצה שנוצר ללא DOMNode. רכיב הקונטיינר בשכבה העליונה הוא הצומת הראשון של ממשק הקצה שאין לו DOMNode. כלומר, הוא קיים רק בממשק העורפי והקצה העורפי לא 'יודע' עליו. כדי שתהיה זהה להתנהגות של צמתים אחרים, יצרנו מחלקה חדשה של TopLayerContainer שמרחיבה את המחלקה UI.TreeOutline.TreeElement, שאחראית להתנהגות של הצמתים האחרים.

כדי להשיג את המיקום הרצוי, המחלקה שמעבדת רכיב מצרפת את TopLayerContainer בתור האח הבא של התג <html>.

תג חדש לשכבה העליונה מציין שהרכיב נמצא בשכבה העליונה ומשמש כקישור לקיצור הדרך של רכיב זה ברכיב TopLayerContainer.

עיצוב ראשוני

בהתחלה, התוכנית הייתה לשכפל רכיבים של השכבה העליונה למאגר של השכבה העליונה, במקום ליצור רשימה של קישורים לרכיבים. לא יישמנו את הפתרון הזה בגלל האופן שבו אחזור הצאצאים של הרכיב פועל בכלי הפיתוח. לכל רכיב יש מצביע הורה המשמש לשליפת ילדים ולא ניתן להשתמש בכמה מצביעים. לכן, אנחנו לא יכולים לקבל צומת שמתרחב ומכיל את כל הצאצאים במספר מקומות בעץ. בדרך כלל, המערכת לא נבנתה תוך מחשבה על תת-עצים כפולים.

הסכנה שבה הגענו הייתה יצירת קישורים לצומתי ה-DOM של ממשק הקצה, במקום לשכפל את הצמתים האלה. הכיתה שאחראית ליצירת קישורים לרכיבים בכלי הפיתוח היא ShortcutTreeElement, שמרחיבה את UI.TreeOutline.TreeElement. ל-ShortcutTreeElement יש התנהגות זהה לזו של רכיבי עץ DOM אחרים של DevTools, אבל אין לו צומת תואם בקצה העורפי ויש לו לחצן שמקשר אל ElementsTreeElement. לכל ShortcutTreeElement בצומת של השכבה העליונה יש צאצא מסוג ShortcutTreeElement שמקשר לייצוג של פסאודו-רכיב ::backdrop בעץ ה-DOM של כלי הפיתוח.

עיצוב ראשוני:

עיצוב ראשוני.

שינויים בפרוטוקול Chrome DevTools (CDP)

כדי להטמיע את התמיכה בשכבה העליונה, צריך לבצע שינויים בפרוטוקול Chrome DevTools (CDP). CDP משמש כפרוטוקול תקשורת בין כלי הפיתוח ל-Chromium.

אנחנו צריכים להוסיף את הפרטים הבאים:

  • פקודה שאפשר להתקשר אליה מהממשק בכל שלב.
  • אירוע שיופעל בקצה העורפי.

CDP: הפקודה DOM.getTopLayerElements

כדי להציג את הרכיבים הנוכחיים של השכבה העליונה, דרושה לנו פקודת CDP ניסיונית חדשה שתחזיר רשימה של מזהי הצמתים של הרכיבים בשכבה העליונה. כלי הפיתוח קורא לפקודה הזו בכל פעם שכלי הפיתוח נפתחים או כשרכיבי השכבה העליונה משתנים. הפקודה נראית כך:

  # Returns NodeIds of the current top layer elements.
  # Top layer renders closest to the user within a viewport, therefore, its elements always
  # appear on top of all other content.
  experimental command getTopLayerElements
    returns
      # NodeIds of the top layer elements.
      array of NodeId nodeIds

CDP: אירוע אחד (DOM.topLayerElementsUpdated)

כדי לקבל את הרשימה העדכנית של רכיבי השכבה העליונה, אנחנו צריכים שכל שינוי ברכיבי השכבה העליונה יפעיל אירוע CDP ניסיוני. האירוע הזה מודיע לממשק הקצה של השינוי שאחר כך קורא לפקודה DOM.getTopLayerElements ומקבל את רשימת הרכיבים החדשה.

האירוע נראה כך:

  # Called by the change of the top layer elements.
  experimental event topLayerElementsUpdated

שיקולי CDP

היו מספר אפשרויות להטמעת התמיכה של CDP בשכבה העליונה. אפשרות אחרת שבדקנו הייתה יצירת אירוע שיחזיר את רשימת הרכיבים בשכבה העליונה, במקום ליידע את ממשק הקצה רק לגבי הוספה או הסרה של רכיב בשכבה העליונה.

לחלופין, אנחנו יכולים ליצור שני אירועים במקום הפקודה: topLayerElementAdded ו-topLayerElementRemoved. במקרה כזה, נקבל רכיב ונצטרך לנהל את מערך רכיבי השכבה העליונה בממשק הקצה.

נכון לעכשיו, אירוע קצה קורא לפקודה getTopLayerElements כדי לקבל רשימה של רכיבים מעודכנים. אם היינו שולחים רשימה של רכיבים או רכיבים ספציפיים שגרמו לשינוי בכל פעם שאירוע מופעל, היינו יכולים להימנע משלב אחד בקריאה לפקודה. עם זאת, במקרה הזה, ממשק הקצה יאבד את השליטה על הרכיבים שיידחפו.

יישמנו אותו כך, כי לדעתנו עדיף שממשק הקצה יחליט מתי לבקש צמתים בשכבה העליונה. לדוגמה, אם השכבה העליונה מכווצת בממשק המשתמש, או שהמשתמש משתמש בחלונית DevTools שאינה כוללת את עץ הרכיבים, אין צורך לקבל את הצמתים הנוספים שעשויים להיות עמוקים יותר בעץ.