Baseline | Widely available
Chrome, Edge, Firefox, Safari에서 지원돼요.
이 기능은 잘 확립되어 있고 많은 기기와 브라우저 버전에서 작동해요. 2022년 3월부터 모든 브라우저에서 사용 가능했어요.
@layer CSS at-rule은 캐스케이드 레이어를 선언하는 데 사용되며, 여러 캐스케이드 레이어가 있을 경우 우선순위 순서를 정의하는 데에도 사용할 수 있어요.
이 데모에서는 @layer를 사용해서 스타일의 우선순위를 어떻게 결정하는지 보여줍니다.
CSS
/* 레이어의 순서를 미리 정해줍니다: module이 먼저, state가 나중입니다.
나중에 나온 레이어(state)가 더 높은 우선순위를 갖습니다. */
@layer module, state;
@layer state {
.alert {
background-color: brown;
}
p {
border: medium solid limegreen;
}
}
@layer module {
.alert {
border: medium solid violet;
background-color: yellow;
color: white;
}
}
HTML
<p class="alert">좀비를 조심하세요 (Beware of the zombies)</p>
/* 문장형 앳 규칙 (statement at-rules) */
@layer layer-name;
@layer layer-name, layer-name, layer-name;
/* 블록형 앳 규칙 (block at-rules) */
@layer {rules}
@layer layer-name {rules}
여기서 사용하는 값들은 다음과 같아요:
layer-name캐스케이드 레이어의 이름입니다.
rules해당 캐스케이드 레이어에 포함될 CSS 규칙들의 집합입니다.
캐스케이드 레이어 내의 규칙들은 한데 묶여서 연쇄(cascade) 반응을 일으키며, 이를 통해 웹 개발자는 캐스케이드에 대해 더 강력한 제어권을 갖게 됩니다. 레이어 안에 정의되지 않은 스타일(일반 스타일)은 이름이 있든 없든 모든 레이어에 선언된 스타일을 항상 덮어씁니다.
아래 다이어그램은 레이어가 1, 2, ..., N 순서로 선언되었을 때의 레이어 우선순위를 보여줍니다.
위 다이어그램에서 알 수 있듯이, !important 플래그가 붙은 중요한 선언(important declarations)은 !important가 없는 일반 선언(normal declarations)보다 우선순위가 높습니다. 그런데 중요한 점은, 중요 규칙들 사이의 우선순위는 일반 규칙의 순서와 반대라는 거예요.
우선순위가 가장 높은 것은 트랜지션(Transitions)입니다. 그다음으로 높은 순위부터 낮은 순위까지 나열하면 다음과 같습니다:
1. 중요한 사용자 에이전트(브라우저) 선언
2. 중요한 사용자 선언 (사용자가 브라우저 설정이나 확장 프로그램 등으로 지정한 스타일)
3. 중요한 제작자(개발자) 선언
사용자는 브라우저 설정이나 운영체제 설정, 확장 프로그램 등을 통해 스타일을 지정할 수 있는데, 이들의 중요한 선언은 우리 개발자가 쓴 중요한 선언보다 우선합니다.
개발자가 작성한 스타일 내에서는, CSS 레이어 내부의 모든 중요한 선언은 레이어 외부의 중요한 선언보다 우선순위가 높습니다. 반면, 일반 선언의 경우 레이어 내부의 스타일은 레이어 외부의 스타일보다 우선순위가 낮습니다.
선언 순서도 중요해요. 먼저 선언된 레이어는 우선순위가 가장 낮고, 마지막에 선언된 레이어가 우선순위가 가장 높습니다. 하지만 !important 플래그를 사용하면 이 우선순위가 거꾸로 뒤집힌답니다.
@layer 앳 규칙은 다음 세 가지 방법 중 하나로 캐스케이드 레이어를 생성할 수 있습니다.
첫 번째 방법은 @layer 블록 규칙을 사용해서 이름을 가진 레이어를 만들고 그 안에 CSS 규칙을 넣는 것입니다:
@layer utilities {
.padding-sm {
padding: 0.5rem;
}
.padding-lg {
padding: 0.8rem;
}
}
두 번째 방법은 @layer 문장 규칙을 사용해서 스타일을 할당하지 않고 쉼표로 구분된 하나 이상의 레이어 이름을 미리 만드는 것입니다. 아래처럼 단일 레이어를 만들 수도 있고요:
@layer utilities;
아래처럼 여러 레이어를 한꺼번에 정의할 수도 있습니다:
@layer theme, layout, utilities;
이 방법이 유용한 이유는 레이어가 선언된 초기 순서가 곧 레이어의 우선순위를 결정하기 때문입니다. 일반적인 선언과 마찬가지로, 여러 레이어에 겹치는 선언이 있다면 마지막에 나열된 레이어가 이깁니다. 따라서 위 예제에서 theme과 utilities 레이어에 서로 충돌하는 규칙이 있다면, utilities 레이어의 규칙이 승리해서 적용됩니다.
이때 utilities 레이어의 규칙은 theme 레이어의 규칙보다 명시도(specificity)가 낮더라도 적용됩니다. 일단 레이어 순서가 확정되면, 명시도나 코드상에 나타난 순서는 무시되기 때문이죠. 덕분에 더 단순한 CSS 선택자를 쓸 수 있게 됩니다. 다른 규칙을 이기기 위해 억지로 명시도를 높일 필요 없이, 그저 더 나중에 나오는 레이어에 배치하기만 하면 되니까요.
참고: 레이어 이름을 선언해서 순서를 정해두었다면, 나중에 같은 이름을 다시 선언해서 CSS 규칙을 추가할 수 있습니다. 이때 스타일은 해당 레이어의 끝에 추가되지만, 전체적인 레이어의 순서는 바뀌지 않습니다.
세 번째 방법은 레이어 이름 없이 @layer 블록 규칙을 사용하는 것입니다. 예를 들면 이렇습니다:
@layer {
p {
margin-block: 1rem;
}
}
이렇게 하면 익명 캐스케이드 레이어(anonymous cascade layer)가 생성됩니다. 이 레이어는 이름이 있는 레이어와 똑같이 작동하지만, 나중에 따로 규칙을 추가할 수 없다는 차이가 있습니다. 익명 레이어의 우선순위는 선언된 순서에 따르며, 레이어 외부에 선언된 스타일보다는 항상 순위가 낮습니다.
레이어를 만드는 또 다른 방법은 @import를 사용하는 것입니다. 이 경우 불러오는 스타일 시트 자체가 레이어가 됩니다. 주의할 점은 @import 규칙은 @charset이나 레이어를 생성하는 @layer 문장(블록 말고 문장입니다!)을 제외한 모든 다른 규칙보다 앞에 와야 한다는 것입니다.
@import "theme.css" layer(utilities);
레이어는 서로 중첩될 수 있습니다. 예를 들면 이렇죠:
@layer framework {
@layer layout {
/* 여기에 스타일 작성 */
}
}
framework 레이어 안에 있는 layout 레이어에 규칙을 추가하고 싶다면, 두 이름을 마침표(.)로 연결하면 됩니다.
@layer framework.layout {
p {
margin-block: 1rem;
}
}
@layer =
@layer <layer-name>? { <rule-list> } |
@layer <layer-name># ;
<layer-name> =
<ident> [ '.' <ident> ]* ```
이 구문은 [CSS Cascading and Inheritance Level 5](https://drafts.csswg.org/css-cascade-5/)의 최신 표준을 반영합니다.
다음 예제에서는 두 개의 CSS 규칙을 만듭니다. 하나는 레이어 외부에 있는 <p> 요소를 위한 것이고, 다른 하나는 type이라는 레이어 내부에 있는 .box p를 위한 것입니다.
레이어가 없다면 .box p 선택자가 명시도가 더 높기 때문에 Hello, world! 텍스트는 초록색(green)으로 표시될 것입니다. 하지만 레이어 외부의 스타일을 담기 위해 생성된 익명 레이어보다 type 레이어가 앞에 오기 때문에(우선순위가 낮기 때문에), 텍스트는 보라색(rebeccapurple)으로 표시됩니다.
또한 선언 순서를 보세요. 레이어 없는 스타일을 코드상에서 먼저 썼음에도 불구하고, 실제로는 레이어 스타일보다 나중에 적용(더 높은 순위)된다는 것을 알 수 있습니다.
<div class="box">
<p>Hello, world!</p>
</div>
p {
color: rebeccapurple;
}
@layer type {
.box p {
font-weight: bold;
font-size: 1.3em;
color: green;
}
}
다음 예제에서는 규칙 없이 레이어 두 개를 먼저 만든 다음, 나중에 해당 레이어들에 CSS 규칙을 할당합니다. base 레이어는 color, border, font-size, padding을 정의하고, special 레이어는 다른 색상을 정의합니다. 레이어를 정의할 때 special이 나중에 나왔기 때문에, 여기서 제공하는 색상이 사용되어 텍스트는 rebeccapurple로 표시됩니다. 물론 색상을 제외한 나머지 base 레이어의 규칙들은 그대로 적용됩니다.
<div class="item">
저는 <code>color: rebeccapurple</code>로 표시됩니다. 왜냐하면 <code>special</code> 레이어가
<code>base</code> 레이어보다 뒤에 선언되었기 때문이죠. 저의 초록색 테두리, 글자 크기, 안쪽 여백은
<code>base</code> 레이어에서 가져온 것입니다.
</div>
/* 레이어 순서를 먼저 정합니다 */
@layer base, special;
@layer special {
.item {
color: rebeccapurple;
}
}
@layer base {
.item {
color: green;
border: 5px solid green;
font-size: 1.3em;
padding: 0.5em;
}
}
@layer는 특히 외부 라이브러리나 프레임워크의 스타일을 내 스타일과 분리해서 관리할 때 정말 유용해요. 복잡한 명시도 전쟁에서 벗어나게 해주는 고마운 기능이죠.