שמות CSS שהוגדרו על ידי המחבר ו-DOM של צל: במפרט ובפועל

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

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

מהם שמות CSS שהוגדרו על ידי המחבר?

שמות CSS שהוגדרו על ידי המחבר הם מנגנון תחביר CSS ישן יחסית, שהוצג במקור לכלל @keyframes, שמגדיר <keyframe-name> בתור מזהה מותאם אישית או מחרוזת. המטרה של המושג הזה היא להצהיר על משהו בחלק אחד של גיליון סגנונות, ולהפנות אליו בחלק אחר.

/* "fade-in" is a CSS name, representing a set of keyframes */
@keyframes fade-in {
  from { opacity: 0 };
  to { opacity: 1 }
}

.card {
  /* "fade-in" is a reference to the above keyframes */
  animation-name: fade-in;
}

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

תכונה הצהרת שם הפניה לשם
תמונות מפתח (keyframes) @keyframes animation-name
גופנים @font-face { }
@font-palette-values
font-family
font-palette
הצהרות על נכסים @property
כל הצהרה על נכס מותאם אישית לא רשום
var()
הצגת המעברים view-transition-name
view-transition-class
::view-transition-* רכיבי פסאודו
מיקום של מודעת עוגן anchor-name position-anchor
אנימציה שמבוססת על גלילה view-timeline-name
scroll-timeline-name
animation-timeline
סגנונות רשימה @counter-style list-style
מונים counter-reset
counter-set
counter-increment
שאילתות בקונטיינרים container-name @container
דף page @page

כפי שאפשר לראות בטבלה, לשם של שירות CSS בדרך כלל יש הפניה תואמת לשירות ה-CSS. לדוגמה, animation-name הוא הפניה לשם @keyframes. שמות ב-CSS שונים משמות שמוגדרים ב-DOM, כמו מאפיינים ושמות תגים, כי הם מוצהרים ולאחר מכן מתבצעת הפניה אליהם בהקשר של סגנונות עימוד.

הקשר בין שמות ל-Shadow DOM

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

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

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

איך השמות וה-DOM בצל צריכים לפעול יחד

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

הכלל הכללי

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

החרגה לכלל: @property

בניגוד לשמות אחרים של CSS, מאפייני CSS לא עטופים ב-shadow DOM. במקום זאת, הם משמשים להעברת פרמטרים בין עצי צל שונים. לכן, התיאור @property הוא מיוחד: הוא אמור לפעול כמו הצהרת סוג ברמת המסמך שמגדירה את האופן שבו פועל מאפיין ספציפי בעל שם. מאחר שהמאפיינים צריכים להתאים בין עצי הצללים, אי-התאמה בהצהרות על המאפיינים תיצור תוצאות בלתי צפויות. לכן, ההצהרות על @property מצוינות כשטוחות וניתנות לפתרון לפי סדר המסמך.

איך הכלל אמור לפעול עם ::part

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

מכיוון ש-::part מאפשר לשני היקפי עץ לעצב את אותו רכיב, מצוין הסדר הבא של מפל:

  1. קודם כל, בודקים את הסגנון בהקשר של ההצללה. זהו הסגנון 'ברירת המחדל' של החלק.
  2. לאחר מכן מחילים את הסגנון החיצוני כפי שמוגדר ב-::part. זהו הסגנון 'המותאם אישית' של החלק.
  3. לאחר מכן, מחילים כל סגנון פנימי שמוגדר יחד עם !important. כך אפשר להצהיר על רכיב מותאם אישית שמאפיין מסוים של חלק מסוים לא ניתן להתאמה אישית באמצעות ::part.

פירוש הדבר הוא שאי אפשר להפנות לשמות מתוך DOM בצל מ-::part, כי ::part הוא סגנון ברמת המארח ולא ברמת הצל. לדוגמה:

// inside the shadow DOM:
@keyframes fade-in {
  from { opacity: 0}
}

// This shouldn't work!
// The host style shouldn't know the name "fade-in"
::part(slider) {
  animation-name: fade-in;  
}

איך הכלל אמור לפעול עם סגנונות בקוד

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

איך שמות CSS ו-DOM בצל פועלים יחד במציאות

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

כדי לבדוק ולהדגים איך התכונות האלה פועלות בפועל, יצרנו את הדף הבא: https://css-names-in-the-shadow.glitch.me/. בדף הזה יש כמה iframes, שכל אחד מהם מתמקד באחת מהתכונות ובוחן שישה תרחישים:

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

@keyframes

כפי שמוגדר במפרט, אפשר להפנות לשמות של תמונות מפתח מתוך שורש צל, כל עוד כלל at-rule‏ @keyframes נמצא בהיקף של אב קדמון. בפועל, אף דפדפן לא מטמיע את ההתנהגות הזו, וניתן להפנות להגדרות של נקודות המפתח רק בהיקף שבו הן מוגדרות. בעיה מס' 10540

@property

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

באגים ספציפיים לדפדפן

התכונות האחרות לא מציגות התנהגות עקבית בדפדפנים השונים:

  • @font-face מוצג ברמת הבסיס (root) ב-Safari.
  • ב-Chromium אסור לרשת כללים של anchor-name ברמה של root בצל
  • ההיקף של scroll-timeline-name ו-view-timeline-name לא נכון ב-::part (וגם ב-Chromium).
  • אף דפדפן לא מאפשר להצהיר על @font-palette-values בשורשי צל.
  • אפשר להגדיר את view-transition-class בתוך root בצל (המעבר עצמו נמצא מחוץ ל-root בצל).
  • ב-Firefox, ל-::part יש גישה לשמות של צללים פנימיים (שאילתות של מאגרים, פריימים מרכזיים).
  • הדפדפנים Firefox ו-Safari לא מכבדים את @counter-style ברמה הבסיסית.

שימו לב של-counter-reset, ‏ counter-set ו-counter-increment יש כללים שונים במקצת, כי הם שמות משתמעים, ולהצהרה על מאפייני CSS יש קבוצת כללים מוגדרת ובדיקה היטב.

סיכום

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