איך בוחרים תחביר לקינון CSS

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

אדם ארגייל
אדם ארגייל
מרים סוזאן
מרים סוזאן

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

.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

לאחר הידור ל-CSS רגיל על ידי המעבד המקדים, נעשה שימוש ב-CSS רגיל באופן הבא:

.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

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

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

למה דוגמת הקינון המדויקת שמוצגת למעלה לא יכולה להיות התחביר של קינון CSS?

יכולות להיות כמה סיבות לכך שלא ניתן להשתמש בתחביר של הסידור הפנימי הפופולרי ביותר:

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

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

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

סקירה כללית על מה שאנחנו משווים

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

אפשרות 1: @nest

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

אפשרות 2: @nest restricted

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

אפשרות 3: סוגריים

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

דוגמה 1 – קינון ישיר

@nest

.foo {
  color: #111;

  & .bar {
    color: #eee;
  }
}

@nest תמיד

.foo {
  color: #111;

  @nest & .bar {
    color: #eee;
  }
}

סוגריים מרובעים

.foo {
  color: #111;

  {
    & .bar {
      color: #eee;
    }
  }
}

CSS שווה ערך

.foo {
  color: #111;
}

.foo .bar {
  color: #eee;
}

דוגמה 2 – קינון מורכב

@nest

.foo {
  color: blue;

  &.bar {
    color: red;
  }
}

@nest תמיד

.foo {
  color: blue;

  @nest &.bar {
    color: red;
  }
}

סוגריים מרובעים

.foo {
  color: blue;

  {
    &.bar {
      color: red;
    }
  }
}

CSS שווה ערך

.foo {
  color: blue;
}

.foo.bar {
  color: red;
}

דוגמה 3 – רשימות בוררים וקינון

@nest

.foo, .bar {
  color: blue;

  & + .baz,
  &.qux {
    color: red;
  }
}

@nest תמיד

.foo, .bar {
  color: blue;

  @nest & + .baz,
  &.qux {
    color: red;
  }
}

סוגריים מרובעים

.foo, .bar {
  color: blue;

  {
    & + .baz,
    &.qux {
      color: red;
    }
  }
}

CSS שווה ערך

.foo, .bar {
  color: blue;
}

:is(.foo, .bar) + .baz,
:is(.foo, .bar).qux {
  color: red;
}

דוגמה 4 – כמה רמות

@nest

figure {
  margin: 0;

  & > figcaption {
    background: lightgray;

    & > p {
      font-size: .9rem;
    }
  }
}

@nest תמיד

figure {
  margin: 0;

  @nest & > figcaption {
    background: lightgray;

    @nest & > p {
      font-size: .9rem;
    }
  }
}

סוגריים מרובעים

figure {
  margin: 0;

  {
    & > figcaption {
      background: lightgray;

      {
        & > p {
          font-size: .9rem;
        }
      }
    }
  }
}

CSS שווה ערך

figure {
  margin: 0;
}

figure > figcaption {
  background: hsl(0 0% 0% / 50%);
}

figure > figcaption > p {
  font-size: .9rem;
}

דוגמה 5 – קינון הורה או שינוי נושא

@nest

.foo {
  color: red;

  @nest .parent & {
    color: blue;
  }
}

@nest תמיד

.foo {
  color: red;

  @nest .parent & {
    color: blue;
  }
}

סוגריים מרובעים

.foo {
  color: red;

  {
    .parent & {
      color: blue;
    }
  }
}

CSS שווה ערך

.foo {
  color: red;
}

.parent .foo {
  color: blue;
}

דוגמה 6 – שילוב של קינון ישיר עם קינון הורה

@nest

.foo {
  color: blue;

  @nest .bar & {
    color: red;

    &.baz {
      color: green;
    }
  }
}

@nest תמיד

.foo {
  color: blue;

  @nest .bar & {
    color: red;

    @nest &.baz {
      color: green;
    }
  }
}

סוגריים מרובעים

.foo {
  color: blue;

  {
    .bar & {
      color: red;

      {
        &.baz {
          color: green;
        }
      }
    }
  }
}

CSS שווה ערך

.foo {
  color: blue;
}

.bar .foo {
  color: red;
}

.bar .foo.baz {
  color: green;
}

דוגמה 7 – קינון שאילתת מדיה

@nest

.foo {
  display: grid;

  @media (width => 30em) {
    grid-auto-flow: column;
  }
}

או באופן מפורש / מורחב

.foo {
  display: grid;

  @media (width => 30em) {
    & {
      grid-auto-flow: column;
    }
  }
}

@Nest תמיד (תמיד מפורש)

.foo {
  display: grid;

  @media (width => 30em) {
    @nest & {
      grid-auto-flow: column;
    }
  }
}

סוגריים מרובעים

.foo {
  display: grid;

  @media (width => 30em) {
    grid-auto-flow: column;
  }
}

או באופן מפורש / מורחב

.foo {
  display: grid;

  @media (width => 30em) {
    & {
      grid-auto-flow: column;
    }
  }
}

CSS שווה ערך

.foo {
  display: grid;
}

@media (width => 30em) {
  .foo {
    grid-auto-flow: column;
  }
}

דוגמה 8 – קבוצות מקננות

@nest

fieldset {
  border-radius: 10px;

  &:focus-within {
    border-color: hotpink;
  }

  & > legend {
    font-size: .9em;
  }

  & > div {
    & + div {
      margin-block-start: 2ch;
    }

    & > label {
      line-height: 1.5;
    }
  }
}

@nest תמיד

fieldset {
  border-radius: 10px;

  @nest &:focus-within {
    border-color: hotpink;
  }

  @nest & > legend {
    font-size: .9em;
  }

  @nest & > div {
    @nest & + div {
      margin-block-start: 2ch;
    }

    @nest & > label {
      line-height: 1.5;
    }
  }
}

סוגריים מרובעים

fieldset {
  border-radius: 10px;

  {
    &:focus-within {
      border-color: hotpink;
    }
  }

  > {
    legend {
      font-size: .9em;
    }

    div {
      + div {
        margin-block-start: 2ch;
      }

      > label {
        line-height: 1.5;
      }
    }}
  }
}

CSS שווה ערך

fieldset {
  border-radius: 10px;
}

fieldset:focus-within {
  border-color: hotpink;
}

fieldset > legend {
  font-size: .9em;
}

fieldset > div + div {
  margin-block-start: 2ch;
}

fieldset > div > label {
  line-height: 1.5;
}

דוגמה 9 – קבוצת קינון מורכבת 'כיור למטבח'

@nest

dialog {
  border: none;

  &::backdrop {
    backdrop-filter: blur(25px);
  }

  & > form {
    display: grid;

    & > :is(header, footer) {
      align-items: flex-start;
    }
  }

  @nest html:has(&[open]) {
    overflow: hidden;
  }
}

@nest תמיד

dialog {
  border: none;

  @nest &::backdrop {
    backdrop-filter: blur(25px);
  }

  @nest & > form {
    display: grid;

    @nest & > :is(header, footer) {
      align-items: flex-start;
    }
  }

  @nest html:has(&[open]) {
    overflow: hidden;
  }
}

סוגריים מרובעים

dialog {
  border: none;

  {
    &::backdrop {
      backdrop-filter: blur(25px);
    }

    & > form {
      display: grid;

      {
        & > :is(header, footer) {
          align-items: flex-start;
        }
      }
    }
  }

  {
    html:has(&[open]) {
      overflow: hidden;
    }
  }
}

CSS שווה ערך

dialog {
  border: none;
}

dialog::backdrop {
  backdrop-filter: blur(25px);
}

dialog > form {
  display: grid;
}

dialog > form > :is(header, footer) {
  align-items: flex-start;
}

html:has(dialog[open]) {
  overflow: hidden;
}

הגיע הזמן להצביע

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

להשתתפות בסקר!