CSS: 캐스케이딩 규칙과 우선순위
이 글에서는 CSS(Cascading Style Sheet)에서 캐스케이딩 규칙과 우선순위에 대해 정리합니다.
CSS: 캐스케이딩 규칙과 우선순위
CSS에서 캐스케이딩(Cascading) 은 "여러 스타일이 한 요소에 겹쳤을 때, 어떤 것을 적용시킬지를 결정하는 규칙" 입니다.
같은 속성에 대한 선언이 여러 개 있어도 정해진 우선순위에 따라 하나의 값만 최종적으로 선택합니다.
CSS: 캐스케이딩
캐스케이딩(Cascading)은 '폭포처럼 흐르다'라는 의미를 가지고 있으며 CSS에서는 위에서 아래로 스타일이 흘러가면서 우선순위에 따라 최종값이 결정되는 과정을 뜻합니다.
하나의 요소와 하나의 속성에 대해 여러 선언이 겹칠 수 있는데 이때 브라우저는 다음과 같은 단계를 거쳐 어떤 값을 쓸지 결정합니다.
이 요소에 실제로 적용 가능한 선언만 필터링 한다. (선택자 매칭, media 쿼리 조건 등).
-
해당 속성에 대한 선언이 있는 경우
- 스타일의 출처(
origin)와!important여부로 "중요도"를 비교한다. - 중요도가 같다면 명시도(
specificity)가 더 높은 쪽을 선택한다. - 명시도까지 같다면 더 나중에 선언된 스타일이 이긴다.
- 스타일의 출처(
-
해당 속성에 대한 선언이 전혀 없는 경우
- 값이 없으면 상속(
inheritance)이나 기본값(initial)로 채운다.
- 값이 없으면 상속(
정리하자면 캐스케이딩은 요소에 스타일을 적용시키기 위해, origin + !important → 명시도 → 선언 순서 → 상속(inheritance)/기본값(initial) 순서로 단계적으로 요소에 적용할 스타일을 결정하는 알고리즘이라고 보면 됩니다.
캐스케이딩: 스타일 출처와 중요도
스타일의 출처(
origin) 와 중요도를 기준으로 그룹을 나눈다.
스타일 출처(origin) 는 아래와 같이 구분할 수 있습니다.
- 사용자 에이전트 스타일시트(User agent stylesheet): 브라우저의 기본 CSS
- 사용자 스타일시트(User stylesheet): 사용자가 추가한 개인 CSS
- 작성자 스타일시트(Author stylesheet): 개발자가 작성한 CSS
일반적으로 사용자 작성자 > 사용자 > 사용자 에이전트 순으로 우선 적용되며 같은 출처 안에서는 !important 가 적용된 스타일이 우선 고려됩니다.
이렇게 스타일의 출처와 중요도를 기준으로 큰 우선순위 그룹을 나눈 뒤, 다음 단계에서 명시도와 선언 순서 등의 규칙이 적용됩니다.
캐스케이딩: 명시도
같은 중요도 그룹 안에서 "선택자가 구체적인 정도"를 숫자로 환산해서 비교 하는데, 이것을 명시도(specificity) 라고 합니다.
명시도는 보통 네 자리의 숫자로 생각할 수 있고, 대략 아래 순서대로 강해집니다.
-
명시도(
specificity) 우선 순위- 인라인 스타일: 요소에 직접
style속성으로 쓴 경우 (예:<p style="color: red">) — 가장 강함. - ID 선택자:
#id형태의 선택자. - 클래스/속성/가상 클래스 선택자:
.class,[type="text"],:hover등. - 태그/가상 요소 선택자:
p,h1,::before등.
- 인라인 스타일: 요소에 직접
-
어떤 스타일이 적용될까
HTML <html> <head> <style> /* p 태그 */ p { color: blue; } /* p 태그 중 intro 라는 클래스를 가진 요소 */ p.intro { color: red; } <style> </head> <body> <p class="intro">어떤 스타일이 적용될까?</p> </body> </html>위 예시에서는
<p class="intro">하나에 대해,p와p.intro두 규칙이 모두 적용될 수 있으나,p는 "모든p태그"를 넓게 잡는 선택자 이고,p.intro는 "intro클래스를 가진p태그"를 더 정확하게 딱 집어서 지정한 선택자 입니다. 이렇게 더 구체적으로 대상 요소를 지정한 선택자의 명시도가 더 높기 때문에p.intro의color값인red가 적용 됩니다.
명시도는 "이 요소에 스타일을 얼마나 정확하게 딱 집어서 적용했는가"를 나타내는 가중치이기 때문에, 선택자를 많이 붙일수록 점수가 계속 올라갑니다. 그렇기 때문에 필요 이상으로 명시도를 높여 복잡하게 만들기보다는, 필요하다면 컴포넌트 단위로 나누는 등 가능하면 단순한 구조와 선택자를 사용하는 것이 좋습니다.
캐스케이딩: 소스 순서
중요도와 명시도까지 완전히 같을 때 마지막으로 적용되는 기준이 소스 순서(source order) 입니다.
같은 요소, 같은 속성, 같은 명시도의 규칙이 여러 개라면, CSS에서 더 나중에 선언된 규칙이 이깁니다.
p {
color: black;
}
p {
color: green;
}
두 규칙은 모두 p에 대해 같은 명시도를 가지기 때문에 나중에 등장한 color: green;이 최종적으로 적용됩니다.
외부 스타일시트를 여러 개 불러오는 경우에도 같은 명시도라면 더 나중에 로드된 파일의 스타일로 덮어쓰게 되는데
이러한 특성을 활용해서 아래와 같은 순서로 구성하여 “뒤에서 덮어쓰기 전략”을 활용해 전체 스타일 구조를 단순하게 유지할 수 있습니다.
- 스타일 구조를 단순하게 하기 위한 전략
reset/normalize.css같은 초기화 스타일을 먼저 로드한다.- 프로젝트 메인 스타일, 컴포넌트 스타일을 그다음에 로드한다.
- 페이지나 상황별 커스텀 스타일이 있다면 가장 마지막에 둔다.
주의할 점
1. !important는 디버깅을 어렵게 만든다
!important로 스타일을 덮으면 이후 수정이 매우 어려워진다. 셀렉터 특이도(specificity)를 이해하고 올바른 셀렉터로 해결하는 것이 맞다.
2. 인라인 스타일은 specificity가 가장 높다
style="" 속성으로 지정한 스타일은 ID 셀렉터보다도 우선한다. CSS 파일에서 아무리 구체적인 셀렉터를 써도 인라인 스타일을 이기지 못한다.