CSS Cascade
여러 출처의 CSS 규칙이 같은 요소에 적용될 때, 최종 승자를 결정하는 알고리즘을 Cascade라고 한다.
Specificity는 Cascade의 한 단계일 뿐이다. 브라우저는 더 넓은 맥락에서 어떤 규칙을 적용할지 결정한다.
판정 순서
Cascade는 다음 순서로 규칙의 우선순위를 결정한다. 위에서부터 먼저 비교하고, 같으면 다음 단계로 넘어간다.
| 순서 | 기준 | 설명 |
|---|---|---|
| 1 | Origin & Importance | 규칙의 출처(브라우저 / 사용자 / 작성자)와 !important 여부 |
| 2 | Cascade Layer | @layer로 정의된 레이어 간 순서 |
| 3 | Specificity | 셀렉터의 무게 (inline > id > class > element) |
| 4 | Source Order | 같은 조건이면 나중에 작성된 규칙이 이김 |
Origin & Importance
CSS 규칙은 출처에 따라 세 가지로 나뉜다.
- 브라우저 기본 스타일 (User Agent) — 브라우저가 내장한 기본 CSS
- 사용자 스타일 (User) — 사용자가 브라우저 설정으로 지정한 CSS
- 작성자 스타일 (Author) — 개발자가 작성한 CSS
일반 규칙은 작성자 > 사용자 > 브라우저 순서다. !important가 붙으면 순서가 뒤집힌다. 브라우저의 !important > 사용자의 !important > 작성자의 !important 순서가 된다.
/* 작성자 스타일 - 일반 */
p { color: black; }
/* 작성자 스타일 - !important */
p { color: red !important; }
!important는 디버깅을 어렵게 만들기 때문에 가능하면 피하는 게 좋다.
Cascade Layer (@layer)
CSS Cascade Layers는 같은 출처 안에서 규칙의 우선순위를 레이어 단위로 제어하는 기능이다.
@layer base, components, utilities;
@layer base {
p { margin: 1em 0; }
}
@layer components {
.card p { margin: 0; }
}
@layer utilities {
.m-0 { margin: 0; }
}
레이어는 선언 순서대로 우선순위가 높아진다. 위 예시에서 utilities > components > base 순이다. Specificity와 무관하게 utilities 레이어의 규칙이 base 레이어를 이긴다. Tailwind CSS가 유틸리티 클래스의 우선순위를 보장하는 원리이기도 하다.
레이어에 속하지 않은 규칙은 모든 레이어보다 높은 우선순위를 가진다.
Next.js에서의 제약
Next.js 14에서 별도 CSS 파일에 @layer를 사용하면 @tailwind 디렉티브를 찾을 수 없다는 에러가 발생할 수 있다. CSS 파일이 독립적으로 처리되기 때문이다. @layer는 Tailwind의 @tailwind 디렉티브가 있는 같은 파일(보통 globals.css) 안에서 사용해야 한다.
Specificity
Cascade에서 Origin, Importance, Layer가 모두 같으면 Specificity를 비교한다. 셀렉터의 무게를 inline > id > class > element 순서로 계산한다. 자세한 내용은 CSS Specificity 노트 참고.
Source Order
모든 조건이 같으면 CSS 파일에서 나중에 작성된 규칙이 이긴다.
p { color: blue; }
p { color: red; } /* 이 규칙이 적용됨 */
<link> 태그나 @import 순서도 영향을 준다. 나중에 로드된 스타일시트가 우선이다.
정리
- Cascade는 Origin → Importance → Layer → Specificity → Source Order 순서로 판정한다
!important는 출처 간 우선순위를 뒤집는다@layer로 같은 출처 안에서 레이어별 우선순위를 제어할 수 있다- Specificity가 같으면 나중에 작성된 규칙이 이긴다