크롬과 사파리에서 CSS 중첩 사용하기
* 《Try out CSS Nesting today》아티클을 번역 및 참고하여 작성한 글입니다.
작년 12월, WebKit은 CSS 중첩에 대한 세 가지 옵션을 자세히 설명하는 아티클을 게시했다.
당시, 아티클에서 옵션 3, 옵션 4, 옵션 5의 차이점을 설명하고 일련의 예시를 통해 각 옵션이 어떻게 작동하는지 보여주었다.
그리고는 "CSS의 미래를 위해 어떤 옵션이 가장 좋을까?"라는 간단한 질문을 던졌다.
- Option 3) Non-letter start: 문자로 시작하지 않는 중첩 스타일 규칙을 선언 블록에 직접 추가
article {
font-family: avenir;
& aside {
font-size: 1rem;
}
}
- Option 4) Postfix block: 스타일 규칙은 스타일 규칙만 포함하는 선언 블록 다음에 두 번째 블록을 선택적으로 넣을 수 있음.
article {
font-family: avenir;
} {
aside {
font-size: 1rem;
}
}
- Option 5) Top-level @nest: 중첩된 스타일 규칙은 스타일 규칙만 허용하는 전용 독립적인 at-rule로 선언, & { .. }를 이용하여 중첩
@nest article {
& {
font-family: avenir;
}
aside {
font-size: 1rem;
}
}
이 설문조사에서 웹 개발자들의 응답은 옵션 3의 압도적인 승리로 나타났다.
이에 따라 WebKit은 사파리와 크롬 브라우저 모두에서 옵션 3을 구현했다.
2023년 1월 25일, Safari Technology Preview 162에서 CSS 중첩이 기본 설정으로 제공되었다.
Mac을 사용하는 경우, Safari 기술 미리보기를 다운로드하여 열고 중첩된 CSS를 작성하여 어떻게 작동하는지 경험할 수 있다.
CSS 중첩은 어떻게 동작하는가
좀 더 간결한 방식으로 작성하고 싶은 CSS 구문을 생각해 보자.
.foo {
color: green;
}
.foo .bar {
font-size: 1.4rem;
}
CSS 중첩을 사용하면 다음과 같이 작성할 수 있다.
.foo {
color: green;
.bar {
font-size: 1.4rem;
}
}
Sass에서 스타일 중첩을 작성해 본 적이 있다면 이 방식이 매우 익숙할 것이다.
하지만 Sass와 달리 이런 종류의 중첩이 항상 동작하지는 않는다.
브라우저 파싱 엔진의 제한으로 인해 중첩된 선택자(위 예제에서는 .bar
)가 항상 기호로 시작하는지 확인해야 한다.
클래스, ID, 가상 클래스, 가상 요소, 속성 선택자, 또는 처음에 기호를 사용하는 선택자라면 가능하다.
예를 들어 .
, #
, :
, [
, *
, +
, >
, ~
와 같이 문자가 아닌 기호로 시작하는 선택자이면 된다.
main {
.bar { ... }
#baz { ...}
:has(p) { ... }
::backdrop { ... }
[lang|="zh"] { ... }
* { ... }
+ article { ... }
> p { ... }
~ main { ... }
}
그러나 선택자 중에는 문자로 시작하는 중첩 요소 선택자가 있다. 다음 예제는 동작하지 않는다.
main {
article { ... }
}
이 코드는 article
선택자가 기호가 아닌 문자로 시작하기 때문에 동작하지 않는다.
article
을 atirlce
처럼 오타로 입력했을 때와 같은 방식으로 실패한다.
특정 선택자에 의존하는 중첩된 CSS는 그냥 무시된다.
이 제한을 해결할 수 있는 몇 가지 옵션이 있다.
가장 자주 사용할 수 있는 해결 방법부터 살펴보자면 다음과 같이 요소 선택자 앞에 &
를 넣으면 된다.
main {
& article { ... }
}
브라우저는 &
기호를 "이 중첩된 블록 외부의 선택자를 여기에서 사용하겠다"로 해석한다.
요소 선택자 앞에 &
를 사용하면 중첩 선택자를 문자가 아닌 기호로 시작하게 되므로 정상적으로 동작한다.
따라서
aside p { ... }
위와 같은 코드는 다음과 같은 중첩 구문으로 표현할 수 있다.
aside {
& p { ... }
}
&
를 유용하게 사용할 수 있는 사례가 더 있다.
다음과 같이 중첩되지 않은 코드를 생각해 보자.
ul {
padding-left: 1em;
}
.component ul {
padding-left: 0;
}
위 코드에서 ul
이 두 번째인 .component ul
이 의도된 선택자임을 알 수 있다.
CSS 중첩을 이용하여 이러한 결과를 산출하려면 다음과 같이 작성하면 된다.
ul {
padding-left: 1em;
.component & {
padding-left: 0;
}
}
다시 말하지만, &
는 중첩된 선택자를 이 위치에 배치할 수 있도록 한다.
또한 &
는 선택자 사이에 공백을 넣고 싶지 않을 때도 유용하다. 예를 들어
a {
color: blue;
&:hover {
color: lightblue;
}
}
위 코드의 중첩 구문은 a:hover
와 동일하게 동작한다.
&
가 없다면 a
와 :hover
사이에 공백이 포함된 a :hover
로 간주되어 hover 상태인 링크의 스타일을 지정할 수 없다.
하지만 다음과 같은 경우엔 어떨까?
ul {
padding-left: 1em;
}
article ul {
padding-left: 0;
}
위의 코드를 중첩 구문으로 다음과 같이 작성하면 안 된다.
ul {
padding-left: 1em;
& article & {
padding-left: 0;
}
}
왜 그럴까? 위 코드는 중첩되지 않은 다음 코드와 동일한 방식으로 동작하기 때문이다.
ul {
padding-left: 1em;
}
ul article ul {
padding-left: 0;
}
우리는 ul article ul
을 의도한 것이 아니다.
중첩 구문을 위해 article &
를 문자가 아닌 기호로 시작하게 하려면 다음과 같이 코드를 작성하면 된다.
ul {
padding-left: 1em;
:is(article) & {
padding-left: 0;
}
}
모든 선택자는 :is()
가상 클래스로 감쌀 수 있으며, 괄호 안의 선택자가 유일한 경우 동일한 특수성과 의미를 유지할 수 있다.
요소 선택자를 :is()
로 감싸면 CSS 중첩의 규칙에 맞게 기호로 시작하는 선택자로 표현할 수 있다.
지금까지의 내용을 요약해 보면 다음과 같다.
CSS 중첩은 Sass와 똑같이 작동하지만, 중첩된 선택자가 항상 기호로 시작해야 한다는 새로운 규칙을 가지고 있다.
현재 파싱 엔진의 속도를 저하시키지 않으면서 이 제한을 해소할 수 있는지에 대한 연구가 진행 중이다.
조만간, 혹은 몇 년 안에 이 제한이 해소될 수도 있을 것이다.
이러한 제한이 없다면 CSS 중첩이 훨씬 더 좋아질 것이라는 데에는 모두가 동의한다.
하지만 웹 페이지가 브라우저 창에 즉시 나타나야 한다는 점에도 모두 동의한다.
렌더링이 시작되기 전에 아주 잠깐이라도 멈추지 않아야 한다.
그렇다면 선택 가능한 것은 무엇일까?
중첩된 코드를 원하는 대로 구성할 수 있는 것이다.
이미 중첩된 CSS 안에 CSS를 중첩하는 등 원하는 만큼의 단계로 중첩할 수 있다.
컨테이너 쿼리, 기능 쿼리, 미디어 쿼리, 캐스케이드 레이어와의 중첩을 원하는 대로 혼합할 수 있다.
어떤 것이든 모든 것 안에 중첩할 수 있다.
지금 바로 CSS 중첩을 사용해 보고 어떤지 확인해 보자.
Experimental Web Platform features를 허용한 크롬 개발자 도구와 Safari Technology Preview에서 코드를 테스트하여 동일한 결과가 나오는지 확인해 보자.
이 새로운 기능이 모든 브라우저에 적용되기 전인 지금이 버그를 찾기에 가장 좋은 시기이다.
bugs.webkit.org 또는 bugs.chromium.org에 이슈를 제보할 수 있다.
또한 몇 가지 다음 버전의 Safari Technology Preview에 대한 릴리스 노트도 눈여겨보자.
각 버전은 CSS 워킹 그룹의 잠재적인 사양 변경에 맞춰 CSSOM 또는 기타 업데이트에 대한 지원을 추가하는 작업을 포함하여 CSS 중첩 구현을 개선할 수 있다.
여러 회사의 많은 사람들이 5년 가까이 CSS에 중첩을 도입하기 위해 노력해 왔다.
CSS 중첩을 위해 여러 가지 솔루션의 장단점에 대한 길고 열띤 토론을 벌여 왔고, 이 결과가 모두에게 큰 도움이 될 것이다.