קינון 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 מהדוגמה הקודמת הוסר מהפרויקט, אפשר למחוק את הקבוצה כולה במקום לחפש בקובצים את המופעים של הבורר הרלוונטי.

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

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

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

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

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

בתוך ארגז החול יש עיגולים, משולשים ומרובעים. חלקם קטנים, בינוניים או גדולים. אחרים הם כחולים, ורודים או סגולים. כולם נמצאים בתוך האלמנט המכיל .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 nesting. מתחת לשאלה הזו תופיע תיבה ירוקה, שמסמנת שהיא נתמכת.

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

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 ב-CSS היא רק בגרסה 1. בגרסה 2 יתווספו עוד תכונות נוחה לשימוש, ויכול להיות שיהיה צורך לשנן פחות כללים. יש ביקוש רב לכך שהניתוח של עץ התצוגה לא יהיה מוגבל או יכלול רגעים בעייתיים.

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

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

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