קינון CSS

אחת מהתכונות האהובות עלינו במעבד CSS מובנית עכשיו בשפה: כללי עיצוב בתצוגת עץ.

Adam Argyle
Adam Argyle

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

לפני
.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

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

אחרי
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

אפשר לנסות את זה בדפדפן.

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

הטמעה בתוך קוד יכולה לעזור: - בארגון - בהקטנת גודל הקובץ - בביצוע Refactoring

אפשר להשתמש באפשרות ההטמעה ב-Chrome מגרסה 112 ואילך, וגם לנסות אותה בגרסת Technical Preview 162 של Safari.

תחילת העבודה עם CSS Nesting

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

רשת צבעונית של מעגלים, משולשים וריבועים קטנים וגדולים.

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

<div class="demo">
  <div class="sm triangle pink"></div>
  <div class="sm triangle blue"></div>
  <div class="square blue"></div>
  <div class="sm square pink"></div>
  <div class="sm square blue"></div>
  <div class="circle pink"></div>
  …
</div>

דוגמאות להטמעה בתוך הטמעה

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

.parent {
  color: blue;

  .child {
    color: red;
  }
}

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

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

.parent {
  color: blue;

  & .child {
    color: red;
  }
}

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

בחירת המעגלים

בדוגמה הראשונה הזו, המשימה היא להוסיף סגנונות כדי להגדיר דעיכה וטשטוש רק של העיגולים בתוך הדמו.

ללא עיטורים, CSS כיום:

.demo .circle {
  opacity: .25;
  filter: blur(25px);
}

עם עיצוב בתצוגת עץ, יש שתי דרכים תקינות:

/* & is explicitly placed in front of .circle */
.demo {
  & .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

או

/* & + " " space is added for you */
.demo {
  .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

התוצאה: כל הרכיבים בתוך .demo עם המחלקה .circle מטושטשים וכמעט בלתי נראים:

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

בחירת משולשים וריבועים

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

ללא עיטורים, ב-CSS יש שתי דרכים:

.demo .triangle,
.demo .square {
  opacity: .25;
  filter: blur(25px);
}

או באמצעות :is()

/* grouped with :is() */
.demo :is(.triangle, .square) {
  opacity: .25;
  filter: blur(25px);
}

עם עיצוב בתצוגת עץ, יש שתי דרכים חוקיות:

.demo {
  & .triangle,
  & .square {
    opacity: .25;
    filter: blur(25px);
  }
}

או

.demo {
  .triangle, .square {
    opacity: .25;
    filter: blur(25px);
  }
}

התוצאה: רק רכיבי .circle נשארים בתוך .demo:

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

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

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

ללא עיטורים, CSS כיום:

.demo .lg.triangle,
.demo .lg.square {
  opacity: .25;
  filter: blur(25px);
}

או

.demo .lg:is(.triangle, .circle) {
  opacity: .25;
  filter: blur(25px);
}

עם עיצוב בתצוגת עץ, יש שתי דרכים חוקיות:

.demo {
  .lg.triangle,
  .lg.circle {
    opacity: .25;
    filter: blur(25px);
  }
}

או

.demo {
  .lg {
    &.triangle,
    &.circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

התוצאה: כל המשולשים והמעגלים הגדולים מוסתרים בתוך .demo:

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

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

.demo {
  .lg {
    .triangle,
    .circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

זוהי דרך תקינה להטמעה, אבל התוצאות לא יהיו תואמות לרכיבים שציפיתם להם. הסיבה לכך היא שאם לא תוסיפו את & כדי לציין את התוצאה הרצויה של .lg.triangle, .lg.circle בשילוב, התוצאה בפועל תהיה .lg .triangle, .lg .circle; בוררי צאצאים.

בחירה של כל הצורות מלבד הצורות הוורודות

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

ללא עיטורים, CSS כיום:

.demo :not(.pink) {
  opacity: .25;
  filter: blur(25px);
}

עם עיצוב בתצוגת עץ, יש שתי דרכים חוקיות:

.demo {
  :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

או

.demo {
  & :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

התוצאה: כל הצורות שלא בצבע ורוד מוסתרות בתוך .demo:

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

נניח שרציתם לטרגט את .demo באמצעות הבורר :not(). & נדרש כדי:

.demo {
  &:not() {
    ...
  }
}

הפונקציה הזו משלבת את .demo ו-:not() ל-.demo:not(), בניגוד לדוגמה הקודמת שבה היה צורך ב-.demo :not(). חשוב מאוד לזכור את ההנחיה הזו כשרוצים להטמיע אינטראקציה מסוג :hover.

.demo {
  &:hover {
    /* .demo:hover */
  }

  :hover {
    /* .demo :hover */
  }
}

דוגמאות נוספות להטמעה בתוך הטמעה

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

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

הטמעת @media

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

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

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    font-size: 1.25rem;
  }
}

אפשר להשתמש ב-& באופן מפורש גם:

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    &.large {
      font-size: 1.25rem;
    }
  }
}

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

מידע נוסף על עריכת כללים ברמה פנימית

עריכת תצוגת עץ בכל מקום

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

.card {
  .featured & {
    /* .featured .card */
  }
}

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

.card {
  .featured & & & {
    /* .featured .card .card .card */
  }
}

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

דוגמאות לקינון לא תקין

יש כמה תרחישים של תחביר עץ שהם לא חוקיים, ויכול להיות שהם יפתיעו אתכם אם השתמשתם בעץ ב-preprocessers.

הטמעה בתוך הטמעה ושרשור

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

.card {
  &--header {
    /* is not equal to ".card--header" */
  }
}

הסבר מפורט יותר זמין במפרט.

דוגמה לניסוח מורכב של עץ

עיבוי בתוך רשימות של בוררים ו-:is()

נבחן את הבלוק הבא של CSS בתצוגת עץ:

.one, #two {
  .three {
    /* some styles */
  }
}

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

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

כדי לסכם בבירור את הדוגמה המורכבת, המערכת תחיל את בלוק ההטמעה הקודם במסמך באופן הבא:

:is(.one, #two) .three {
  /* some styles */
}

חשוב לשים לב או ללמד את ה-linters להזהיר כשיש עיטורים בתוך רשימת בוררים שמשתמשת בבורר מזהה. רמת הספציפיות של כל העיטורים בתוך רשימת הבוררים הזו תהיה גבוהה.

שילוב של עיטורים והצהרות

נבחן את הבלוק הבא של CSS בתצוגת עץ:

.card {
  color: green;
  & { color: blue; }
  color: red;
}

הצבע של האלמנטים .card יהיה blue.

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

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

.card {
  color: green;
  & { color: blue; }
  & { color: red; }
}

למעשה, מומלץ לעטוף כל סגנון שמופיע אחרי עיצוב עץ ב-&.

.card {
  color: green;

  @media (prefers-color-scheme: dark) {
    color: lightgreen;
  }

  & {
    aspect-ratio: 4/3;
  }
}

זיהוי תכונות

יש שתי דרכים מצוינות לזהות תכונות בתוך עץ CSS: שימוש בעץ או שימוש ב-@supports כדי לבדוק אם יש יכולת לנתח סלקטורים בתוך עץ.

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

שימוש בהטמעה:

html {
  .has-nesting {
    display: block;
  }

  .no-nesting {
    display: none;
  }
}

באמצעות @supports:

@supports (selector(&)) {
  /* nesting parsing available */
}

הקולגה שלי Bramus פרסם קוד מצוין ב-Codepen שמראה איך משתמשים בשיטה הזו.

ניפוי באגים באמצעות כלי הפיתוח ל-Chrome

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

צילום מסך של תחביר ההטמעה של כלי הפיתוח ל-Chrome.

ב-Chrome 113 תהיה תמיכה נוספת ב-CSS בתוך CSS. כדאי להתעדכן בהמשך.

העתיד

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

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

לסיום, כאן תוכלו לראות הדגמה שבה נעשה שימוש ב-@scope, בהטמעת עץ וב-@layer יחד. זה כל כך מרגש!

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