CSS 중첩

이제 가장 좋아하는 CSS 전처리기 기능 중 하나인 스타일 규칙 중첩이 언어에 내장되었습니다.

중첩하기 전에 모든 선택자는 서로 별도로 명시적으로 선언되어야 했습니다. 이로 인해 반복, 스타일시트 대량, 분산된 작성 환경이 발생합니다.

이전
.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부터 사용할 수 있으며 Safari 기술 미리보기 162에서 사용해 볼 수도 있습니다.

CSS 중첩 시작하기

이 게시물의 나머지 부분에서는 선택사항을 시각화하는 데 도움이 되는 다음 데모 샌드박스를 사용합니다. 이 기본 상태에서는 아무것도 선택되지 않고 모든 항목이 표시됩니다. 다양한 도형과 크기를 선택하여 문법을 연습하고 작동하는 모습을 확인할 수 있습니다.

크고 작은 원, 삼각형, 정사각형으로 이루어진 다채로운 그리드

샌드박스 안에는 원, 삼각형, 정사각형이 있습니다. 일부는 소형, 중형, 대형입니다. 다른 색상은 파란색, 분홍색 또는 보라색입니다. 모두 .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);
  }
}

결과: .circle 클래스가 있는 .demo 내의 모든 요소가 흐리게 처리되어 거의 보이지 않습니다.

도형의 다채로운 그리드에 더 이상 원이 없으며 배경에 매우 희미하게 표시됩니다.
데모 사용해 보기

삼각형과 정사각형 선택

이 작업을 수행하려면 중첩된 여러 요소(그룹 선택자라고도 함)를 선택해야 합니다.

중첩 없이 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);
  }
}

결과: .demo 내에 .circle 요소만 남습니다.

다양한 도형으로 이루어진 격자에는 원만 남아 있고 다른 도형은 거의 보이지 않습니다.
데모 사용해 보기

큰 삼각형과 원 선택

이 작업에는 복합 선택기가 필요합니다. 요소가 선택되려면 두 클래스가 모두 있어야 합니다.

중첩 없이 오늘날 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 내에 숨겨집니다.

이제 다채로운 그리드가 흑백으로 바뀌고 분홍색 도형만 표시됩니다.
데모 사용해 보기
&를 통한 정밀도 및 유연성

:not() 선택기로 .demo를 타겟팅하려고 한다고 가정해 보겠습니다. &는 다음과 같은 경우에 필수입니다.

.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 카드를 타겟팅하여 추가 중첩 기능이 계속 작동하는 것을 보여줍니다.

@rules 중첩에 대해 자세히 알아보세요.

어디서나 중첩

지금까지의 모든 예시는 이전 컨텍스트를 계속하거나 추가했습니다. 필요한 경우 컨텍스트를 완전히 변경하거나 재정렬할 수 있습니다.

.card {
  .featured & {
    /* .featured .card */
  }
}

& 기호는 문자열이 아닌 선택기 객체에 대한 참조를 나타내며 중첩된 선택기의 아무 곳이나 배치할 수 있습니다. 여러 번 배치할 수도 있습니다.

.card {
  .featured & & & {
    /* .featured .card .card .card */
  }
}

이 예시는 약간 쓸모없어 보이지만 선택기 컨텍스트를 반복할 수 있는 것이 유용한 경우가 분명히 있습니다.

잘못된 중첩 예시

중첩 문법 시나리오 중에는 잘못된 것이 있으며, 프리프로세서에서 중첩을 사용해 왔다면 놀랄 수 있습니다.

중첩 및 연결

많은 CSS 클래스 이름 지정 규칙은 중첩을 통해 선택자를 문자열처럼 연결하거나 추가할 수 있다고 가정합니다. 선택자가 문자열이 아닌 객체 참조이므로 CSS 중첩에서는 작동하지 않습니다.

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

자세한 내용은 사양을 참고하세요.

까다로운 중첩 예시

선택기 목록 및 :is() 내에서 중첩

다음과 같은 중첩 CSS 블록을 고려해 보세요.

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

선택자 목록으로 시작하여 계속 중첩되는 첫 번째 예입니다. 이전 예에서는 선택기 목록으로만 끝났습니다. 이 중첩 예시에는 잘못된 것이 없지만, 특히 ID 선택기가 포함된 선택자 목록 내에서 중첩하는 것과 관련하여 구현 세부정보가 약간 까다로울 수 있습니다.

중첩의 의도가 작동하려면 가장 안쪽 중첩이 아닌 모든 선택자 목록이 브라우저에 의해 :is()로 래핑됩니다. 이 래핑은 작성된 컨텍스트 내에서 선택기 목록의 그룹화를 유지합니다. 이 그룹화(:is(.one, #two))의 부작용은 괄호 안의 선택기 내에서 가장 높은 점수의 특이성을 채택한다는 점입니다. 이는 :is()가 항상 작동하는 방식이지만 중첩 문법을 사용할 때는 작성된 내용과 정확히 일치하지 않으므로 놀랄 수 있습니다. 요약하면 ID 및 선택기 목록으로 중첩하면 매우 높은 특이성 선택기가 생성될 수 있습니다.

어려운 예를 명확하게 요약하기 위해 이전 중첩 블록이 다음과 같이 문서에 적용됩니다.

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

ID 선택기를 사용하는 선택자 목록 내에서 중첩할 때 주의하거나 린터에 경고하도록 지시하세요. 이 선택자 목록 내의 모든 중첩의 특이성이 높습니다.

중첩과 선언 혼합

다음과 같은 중첩 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를 사용하여 중첩 선택자 파싱 기능을 확인합니다.

브라우저에서 CSS 중첩을 지원하는지 묻는 Bramus의 Codepen 데모 스크린샷입니다. 이 질문 아래에는 지원을 나타내는 녹색 상자가 있습니다.

중첩 사용:

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

  .no-nesting {
    display: none;
  }
}

@supports 사용:

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

제 동료 Bramus가 이 전략을 보여주는 멋진 Codepen을 작성했습니다.

Chrome DevTools로 디버깅

현재 DevTools에서 중첩을 지원하는 기능은 매우 적습니다. 현재 스타일이 예상대로 스타일 창에 표시되지만 중첩 및 전체 선택자 컨텍스트의 추적은 아직 지원되지 않습니다. 이를 투명하고 명확하게 만들기 위한 설계와 계획이 있습니다.

Chrome DevTools 중첩 문법의 스크린샷

Chrome 113에서는 CSS 중첩을 추가로 지원할 계획입니다. 조금만 더 기다려 주시기 바랍니다.

앞으로

CSS 중첩은 버전 1만 있습니다. 버전 2에서는 더 많은 문법 설탕과 더 적은 암기 규칙이 도입됩니다. 중첩 파싱이 제한되지 않거나 까다로운 순간이 없도록 하는 데 대한 수요가 많습니다.

중첩은 CSS 언어의 큰 개선사항입니다. CSS의 거의 모든 아키텍처 측면에 작성 관련 의미가 있습니다. 버전 2를 효과적으로 지정하려면 이러한 큰 영향을 깊이 탐구하고 이해해야 합니다.

마지막으로 @scope, 중첩, @layer를 모두 사용하는 데모를 확인해 보세요. 정말 흥미로운 소식입니다.

회색 배경에 밝은 카드가 있습니다. 카드에는 제목과 텍스트, 몇 가지 작업 버튼, 사이버 펑크 스타일 이미지가 있습니다.