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 */
}

제 동료인 브라머스가 이 전략을 보여주는 훌륭한 Codepen을 맡고 있습니다.

Chrome DevTools로 디버깅

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

Chrome DevTools 중첩 구문의 스크린샷

Chrome 113에서는 CSS 중첩을 추가로 지원할 계획입니다. 많은 기대 바랍니다.

앞으로

CSS 중첩은 버전 1에서만 제공됩니다. 버전 2는 더 많은 구문 코드를 도입하고 기억해야 할 규칙이 줄어들 수 있습니다. 중첩 파싱이 제한되거나 까다로운 순간이 되어야 하는 수요가 많습니다.

중첩은 CSS 언어가 크게 개선된 기능입니다. 이는 CSS의 거의 모든 아키텍처 측면에서 작성에 영향을 미칩니다 버전 2를 효과적으로 지정하려면 이러한 큰 영향을 자세히 살펴보고 이해해야 합니다.

마지막으로 @scope, 중첩, @layer를 모두 사용하는 데모를 확인하세요. 모두 매우 흥미롭습니다.

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