קינון 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 וגם לניסיון ב-Safari Technical Preview 162.

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

בהמשך הפוסט הזה נשתמש בארגז החול להדגמה (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 */
  }
}

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

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

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

קינון ושרשור

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

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

אפשר למצוא הסבר מפורט יותר במפרט.

דוגמה לקינון בעייתי

נמצא ברשימות בוררים ו-:is()

נבחן את בלוק ה-CSS הבא של ה-CSS:

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

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

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

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

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

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

שילוב של סידור והצהרות

נבחן את בלוק ה-CSS הבא של ה-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 כדי לבדוק את יכולת הניתוח של בורר ההצבה.

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

שימוש בסידור פנימי:

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

  .no-nesting {
    display: none;
  }
}

באמצעות @supports:

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

לקולגה שלי, Bramus, יש קודפ מעולה שמלמד את האסטרטגיה הזו.

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

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

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

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

העתיד

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

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

לסיום, הנה הדגמה שמשתמשת ב-@scope, במיקום קבוע וב-@layer ביחד. זה ממש מרגש!

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