"!important 는 specificity 이해 못 했을 때의 답이야. 답은 specificity 를 이해하는 거."
Specificity 가 뭐야?
Specificity 는 CSS 가 각 selector 에 계산하는 숫자 점수. 여러 규칙이 충돌하는 선언으로 같은 element 를 타깃할 때, 가장 높은 specificity 가진 selector 가 이김. Specificity 동점이면 source 순서에서 나중에 오는 규칙이 이김.
그게 알고리즘 전체. 어려운 부분은 맞게 계산하는 거.
네 컬럼 점수: (a, b, c, d)
Specificity 는 네 카운트의 튜플, 왼쪽-오른쪽으로 비교:
- a — 인라인 스타일: 선언이
style="..."attribute 안이면 1, 아니면 0. - b — ID:
#idselector 개수. - c — class, attribute, pseudo-class:
.class,[attr],:hover,:nth-child등의 개수. - d — element 와 pseudo-element:
div,::before등의 개수.
튜플 비교 왼쪽-오른쪽: a 의 어떤 차이든 결정; a 동점이면 b 봐; 이런 식. 이건 10 진수 산술이 아니야. Class 10 개 (0,0,10,0) 가 ID 1 개 (0,1,0,0) 안 이김 — ID 가 더 높은 컬럼.
손으로 계산한 예
p→ (0,0,0,1)p.lead→ (0,0,1,1)article p.lead→ (0,0,1,2)article p.lead.featured→ (0,0,2,2)#main p→ (0,1,0,1)nav a:hover→ (0,0,1,2)a[href^="https"]→ (0,0,1,1)style="color: red"→ (1,0,0,0):where(.btn, .button)→ (0,0,0,0) — :where 는 항상 0 기여:is(.btn, #cta)→ (0,1,0,0) — :is 는 가장 높은 argument 의 specificity 받음:not(.btn, #cta)→ (0,1,0,0) — :is 와 같은 규칙
!important override
선언에 !important 더하면 cascade 의 더 높은 tier 로 이동 — specificity 와 무관하게 모든 non-!important 선언 이김. !important 두 개는 다시 specificity 로 경쟁.
!important 는 거의 항상 잘못된 답. "왜 내 규칙이 안 이기는지 못 알아내서 escalate 했음" 신호. 옳은 답은 보통:
- 본인 selector 의 specificity 를 경쟁자에 맞게 올림.
- 충돌하는 규칙을 덜 specific 하게 리팩토링.
- Cascade layer (Track 7 의 레슨) 써서 순서 명시적으로 제어.
!important 의 정당한 사용은 좁아: 접근성 위해 작성자 스타일 override 해야 하는 사용자 스타일시트, 항상 이기게 의도된 utility 클래스 (Tailwind 의 plugin override 가 이렇게 함), 그리고 가끔의 서드파티 라이브러리 override.
디자인 시스템용 :where() 마법
:where() 가 :is() 와 같은 selector 매치하지만 항상 specificity (0,0,0,0) 보고. 디자인 시스템이 필요로 하는 정확히 그것: 어떤 작성자 규칙이 단일 class 로 override 할 수 있는 베이스 스타일:
DevTools 에서 Specificity 읽기
Chrome DevTools 가 Styles 패널에서 각 규칙 옆에 specificity 보여 줘: selector 텍스트 hover 하면 툴팁이 (a,b,c,d) 점수 표시. Firefox 도 비슷. 디버깅 가장 빠른 방법: "왜 파란 스타일이 이기지? 아, 저 다른 규칙에 못 본 ID 가 있었네."
Cascade 순서, 전체
두 규칙이 적용되면, 브라우저가 이 정렬된 리스트 걷고 첫 결정적 비교가 이김:
- Origin 과 importance — user-important > author-important > author > user > UA-default (그리고 UA-important 는 모든 user 아래).
- Cascade layer — 늦게 선언된 layer 가 일찍 선언된 거 이김 (Track 7).
- Specificity — 방금 계산한 점수.
- Source 순서 — 늦게 쓴 규칙이 이김.
피파의 노트
:where() 쓰고 ID 는 전혀 피해. 다른 스택, 같은 교훈: specificity 전략 골라서 고수.