CSS 중첩 구문 선택 도움말

두 가지 경쟁 구문이 사양 후보로 옹호되어야 하는지 결정하는 데 도움이 필요합니다.

CSS 중첩은 규칙 집합 내에 CSS를 추가할 수 있는 편리한 구문 추가 기능입니다. SCSS, Less 또는 Stylus를 사용한 적이 있다면 다음과 같은 몇 가지 변형을 본 적이 있을 것입니다.

.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 중첩의 문법이 될 수 없는 이유는 무엇인가요?

가장 인기 있는 중첩 구문을 그대로 사용할 수 없는 몇 가지 이유가 있습니다.

  1. 모호한 파싱
    일부 중첩 선택기는 속성 및 전처리기와 정확히 유사하며 빌드 시에 이를 해결하고 관리할 수 있습니다. 브라우저 엔진의 어포던스가 동일하지 않으므로 선택기는 느슨하게 해석해서는 안 됩니다.

  2. 전처리기 파싱 충돌
    CSS의 중첩 방식은 전처리기나 기존 개발자 중첩 워크플로를 중단해서는 안 됩니다. 이는 해당 생태계와 커뮤니티에 방해가 되고 배려가 없는 행동입니다.

  3. :is() 대기
    기본 중첩에는 :is()가 필요하지 않지만 더 복잡한 중첩에는 필요합니다. 선택기 목록과 중첩에 관한 간단한 소개는 예 3을 참고하세요. 선택기 목록이 선택기의 시작 부분이 아닌 중간에 있다고 가정해 보겠습니다. 이 경우 다른 선택기의 중간에 선택기를 그룹화하려면 :is()가 필요합니다.

비교 대상 개요

CSS 중첩을 올바르게 구현하기 위해 커뮤니티를 포함하고 있습니다. 다음 섹션에서는 Google에서 평가하는 세 가지 가능한 버전을 설명합니다. 그런 다음 비교를 위해 사용 사례를 살펴보고 마지막에 전반적으로 선호하는 항목을 묻는 간단한 설문조사가 진행됩니다.

옵션 1: @nest

이는 CSS Nesting 1에 현재 지정된 구문입니다. &로 새로운 중첩 선택기를 시작하여 추가 스타일을 중첩하는 편리한 방법을 제공합니다. 또한 주제를 추가하는 것뿐만 아니라 새 선택기 내부에 & 컨텍스트를 배치하는 방법으로 @nest를 제공합니다. 유연하고 최소한의 기능만 제공하지만 사용 사례에 따라 @nest 또는 &를 기억해야 합니다.

옵션 2: @nest 제한

이는 두 가지 중첩 방법을 기억하는 데 드는 비용을 줄이기 위한 더 엄격한 대안입니다. 이 제한된 구문은 @nest 다음에만 중첩이 발생하도록 허용하므로 추가 전용 편의 패턴이 없습니다. 선택의 모호성을 제거하고 기억하기 쉬운 중첩 방법을 만들지만 관례를 위해 간결성을 희생합니다.

옵션 3: 괄호

@nest 제안과 관련된 이중 구문이나 추가적인 혼란을 피하기 위해 미리암 수잔엘리카 에테마드는 추가 중괄호에 의존하는 대체 구문을 제안했습니다. 이렇게 하면 두 개의 추가 문자만 있고 새로운 @규칙이 없어 구문이 명확해집니다. 또한 여러 유사한 중첩 선택기를 간소화하는 방법으로 필요한 중첩 유형별로 중첩된 규칙을 그룹화할 수 있습니다.

예 1 - 직접 중첩

@nest

.foo {
  color: #111;

  & .bar {
    color: #eee;
  }
}

@nest always

.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 always

.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 always

.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 always

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 always

.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 always

.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 always (항상 명시적임)

.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 always

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 always

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;
}

투표 시간

이것이 공정한 비교이자 Google에서 평가 중인 구문 옵션의 샘플 모음이라고 생각되기를 바랍니다. 아래에서 신중하게 검토한 후 선호하는 옵션을 알려주세요. CSS 중첩을 모두가 알고 좋아하는 구문으로 발전시키는 데 도움을 주셔서 감사합니다.

설문조사 참여하기