ช่วยเลือกไวยากรณ์สำหรับการซ้อน CSS

ไวยากรณ์ที่แข่งขัน 2 รูปแบบต้องการความช่วยเหลือจากคุณในการพิจารณาว่าควรสนับสนุนข้อความใดที่มีคุณสมบัติตามเกณฑ์

อดัม อาร์ไกล์
อดัม อาร์ไกล์
มีเรียม ซูซาน
Miriam Suzanne

การซ้อน CSS เป็นการเพิ่มไวยากรณ์ตามความสะดวกที่ช่วยให้เพิ่ม CSS ภายในชุดกฎได้ ถ้าคุณเคยใช้ SCSS, Less หรือ Stylus แสดงว่าคุณน่าจะเคยเห็น 2-3 รสชาติต่อไปนี้

.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

ซึ่งหลังจากที่ Preprocessor รวบรวมไปยัง CSS ปกติแล้ว ก็จะเปลี่ยนเป็น CSS ปกติดังนี้

.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

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

เรากำลังพิจารณาเวอร์ชัน CSS อย่างเป็นทางการของไวยากรณ์นี้ และเราต้องการให้มีการแยกส่วนกัน เราต้องการใช้ความช่วยเหลือของชุมชนเพื่อทำลายความสัมพันธ์ ส่วนที่เหลือในโพสต์นี้จะนำเสนอตัวเลือกไวยากรณ์เพื่อให้คุณได้ทำแบบสำรวจในตอนท้าย

ทําไมตัวอย่างการซ้อนกันตามที่แสดงด้านบนจึงเป็นไวยากรณ์สําหรับการซ้อน CSS ไม่ได้

มีสาเหตุ 2-3 ประการที่ทำให้ไม่สามารถใช้ไวยากรณ์ที่ซ้อนกันซึ่งเป็นที่นิยมมากที่สุดได้ ดังนี้

  1. การแยกวิเคราะห์ไม่ชัดเจน
    ตัวเลือกที่ฝังอยู่บางตัวอาจมีลักษณะเหมือนพร็อพเพอร์ตี้และตัวประมวลผลล่วงหน้า แก้ไขและจัดการได้ในเวลาบิลด์ เครื่องมือของเบราว์เซอร์ไม่มีโอกาสแบบเดียวกัน ตัวเลือกจึงไม่ควรตีความแบบหลวมๆ

  2. ความขัดแย้งในการแยกวิเคราะห์ของผู้ประมวลผลข้อมูลล่วงหน้า
    วิธีการซ้อนของ CSS นั้นไม่ควรละเมิดกระบวนการก่อนการประมวลผลหรือเวิร์กโฟลว์ที่ซ้อนกันของนักพัฒนาแอปที่มีอยู่ การดําเนินการนี้จะก่อให้เกิดการหยุดชะงักและไม่พิจารณา ระบบนิเวศและชุมชนเหล่านั้น

  3. กำลังรอ :is()
    การซ้อนพื้นฐานไม่จำเป็นต้องใช้ :is() แต่การซ้อนที่ซับซ้อนกว่านั้นทำได้ ดูตัวอย่างที่ 3 สำหรับข้อมูลเบื้องต้นเกี่ยวกับรายการตัวเลือกและการซ้อน สมมติว่ารายการตัวเลือกอยู่ตรงกลางของตัวเลือกแทนที่จะอยู่ช่วงต้น ในกรณีเหล่านั้น ต้องใช้ :is() เพื่อจัดกลุ่มเครื่องมือเลือกไว้ตรงกลางของตัวเลือกอื่น

ภาพรวมของสิ่งที่เรากำลังเปรียบเทียบ

เราต้องการให้ CSS มีการซ้อนอย่างถูกต้อง และด้วยเหตุนี้ เราจึงรวมชุมชนไว้ด้วย ส่วนต่อไปนี้จะช่วยอธิบายถึงเวอร์ชันที่เป็นไปได้ 3 เวอร์ชันที่เราประเมิน จากนั้นเราจะพูดถึงตัวอย่างการใช้งานเพื่อเปรียบเทียบ และในช่วงท้ายจะมีแบบสำรวจสั้นๆ ที่ถามคุณว่าโดยรวมคุณชอบอะไร

ตัวเลือกที่ 1: @nest

นี่คือไวยากรณ์ที่ระบุในปัจจุบันในการซ้อน CSS 1 วิธีนี้มอบวิธีที่สะดวกในการฝังสไตล์การต่อท้ายด้วยการเริ่มเครื่องมือเลือกแบบซ้อนใหม่ด้วย & และยังมี @nest เป็นวิธีวางบริบท & ที่ใดก็ได้ภายในตัวเลือกใหม่ เช่น เมื่อคุณไม่ได้เพิ่มเฉพาะวัตถุ ตัวเลือกนี้มีความยืดหยุ่นและน้อย แต่ก็ต้องจ่ายค่าจำ @nest หรือ & ตามกรณีการใช้งานของคุณ

ตัวเลือกที่ 2: @nest ถูกจำกัด

นี่เป็นอีกทางเลือกหนึ่งที่เข้มงวดกว่า โดยพยายามลดค่าใช้จ่ายที่กล่าวถึงการจำวิธีการซ้อน 2 วิธีการ ไวยากรณ์ที่จำกัดนี้อนุญาตให้ซ้อนเกิดขึ้นหลัง @nest เท่านั้น ดังนั้นจึงไม่มีรูปแบบความสะดวกสบายต่อท้ายเท่านั้น ขจัดความคลุมเครือของทางเลือก สร้างวิธีหนึ่งที่จดจำง่าย แต่มีความเสียสละเพื่อยึดถือตามธรรมเนียม

ตัวเลือกที่ 3: วงเล็บเหลี่ยม

Miriam Suzanne และ Elika Etemad ได้เสนอไวยากรณ์ทางเลือกที่ใช้วงเล็บปีกกาเพิ่มเติมเพื่อหลีกเลี่ยงไม่ให้รูปแบบ 2 ชั้นหรือทำให้สับสนเป็นพิเศษจากข้อเสนอ @nest วิธีนี้ทำให้ไวยากรณ์มีความชัดเจน โดยใช้อักขระเพิ่มอีก 2 ตัว และไม่มีกฎใหม่ นอกจากนี้ยังช่วยให้สามารถจัดกลุ่มกฎที่ซ้อนกันตามประเภทของการซ้อนที่ต้องการ ซึ่งเป็นวิธีลดความซับซ้อนของตัวเลือกที่ซ้อนกันที่คล้ายกัน

ตัวอย่างที่ 1 - การซ้อนโดยตรง

@ฝัง

.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 - การฝังแบบผสม

@ฝัง

.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 - รายการตัวเลือกและการซ้อน

@ฝัง

.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 - หลายระดับ

@ฝัง

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 - การซ้อนผู้ปกครองหรือการเปลี่ยนเรื่อง

@ฝัง

.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 - การผสมโดยตรงและการซ้อนระดับบนสุด

@ฝัง

.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 - การซ้อนคิวรี่สื่อ

@ฝัง

.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 - กลุ่มที่ซ้อนกัน

@ฝัง

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 - กลุ่มที่ซ้อนกันแบบซ้อน "อ่างล้างจาน"

@ฝัง

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 ในไวยากรณ์ที่เรา ทุกคนรู้จักและชื่นชอบ!

ตอบแบบสำรวจ