CSS 캐스캐이딩(Cascading)
요소는 하나 이상의 CSS 선언에 영향을 받을 수 있다. 이때 충돌을 피하기 위해 CSS 적용 우선순위가 필요한데 이를 캐스캐이딩(Cascading Order)이라고 한다.
캐스캐이딩에는 다음과 같이 세가지 규칙이 있다.
- 중요도 : CSS가 어디에 선언 되었는지에 따라서 우선순위가 달라진다.
- 명시도 : 대상을 명확하게 특정할수록 명시도가 높아지고 우선순위가 높아진다.
- 선언순서 : 선언된 순서에 따라 우선 순위가 적용된다. 즉, 나중에 선언된 스타일이 우선 적용된다.
🚀강력한 순서는 중요도 > 명시도 > 선언순서 이다.(왼쪽이 가장 강하다.)
CSS 중요도
CSS가 어디에 선언 되었는지에 따라서 우선순위가 달라진다.(1번쪽이 가장 강력)
- head 요소 내의 style 요소
- head 요소 내의 style 요소 내의 @import 문
- `<link >`로 연결된 CSS 파일
- `<link >`로 연결된 CSS 파일 내의 @import 문
- 브라우저 디폴트 스타일시트
참고로 보통 우리가 프로젝트에서 쓰는 css 파일은 link태그에서 stylesheet로 불러와서 쓰고 있으므로 3번에 해당한다. 그 내부에서 `@import`를 쓰면 4번에 해당한다.
CSS 명시도
대상을 명확하게 특정할수록 명시도가 높아지고 우선순위가 높아진다.(1번쪽이 가장 강력)
- !important
- 인라인 스타일
- 아이디 선택자
- 클래스 / 어트리뷰트 / 가상 선택자
- 태그 선택자
- 전체 선택자
- 상위 요소에 의해 상속된 속성
선언순서
나중에 선언한 스타일이 우선순위가 더 높다.(나중에 선언한 게 가장 강력)
선택자 우선순위
선택자 우선순위란 같은 요소가 여러 선언의 대상이 된 경우, 어떤 선언의 CSS 속성을 우선적으로 적용할 것인지를 결정하는 방법이다.
그 기준은 다음과 같다.
- 점수가 높은 선언이 우선함.
- 점수가 같으면, 가장 마지막에 해석된(작성된) 선언이 우선함
- 점수는 비유가 아니라 리얼 real 반영되는 진짜 점수임.
🚨주의사항
아래 점수를 읽기 전에 주의사항이 한 가지 있다.
점수의 비교는 같은 랭크끼리만 비교된다는 점을 알아야 한다.
태그 선택자 100개가 모여서 아무리 점수가 높아도 1개의 클래스 선택자를 이길 수는 없다. 랭크가 다르기 때문이다.
예를 들어 id가 2개 있고 class가 하나 일치하는 1번과 id가 1개 있고 class가 100만 개 일치하는 2번과 싸우면 1번이 이긴다.
즉, 점수가 아무리 높아도 우선 순위에 급이 있다는 것이다.
우리나라의 올림픽 메달 집계 순위 시스템에 빗대어 보면 이해가 쉽다.
금메달이 많은 쪽이 1등인 것이다.
그 우선순위는 다음과 같다.!important > #id > .class, [attribute] > tag
좌측에 가까운 게 많이 일치하면 우측에 일치하는 게 아무리 많아도 좌측이 급이 높아서 이긴다. (class와 attribute는 동일하며 비교할 수 있는 동일 랭크에 위치함.)
선택자 점수 매기기
!important: 무한대!important를 속성 값 옆에 작성하면 우선순위가 가장 높게 부여된다.
div {
color: red !important;
}
- 인라인 선언 방식: 1000점
인라인 선언 방식은 html 문서 내부에서 style 속성에 직접 스타일을 작성하는 방식인데요. 인라인 방식으로 작성하게 되면 우선순위가 너무 높기 때문에 css에서 !important를 써주지 않는 이상 같은 스타일 속성에 한해서는 다른 값으로 덮을 수 없게 된다.
<div>
<p style="color: red;">Contents</p>
</div>
- id 선택자: 100점
#name {
color: red;
}
- class 선택자: 10점 / attribute 선택자: 10점
.name {
color: red;
}
가상 클래스
(:nth-child, :nth-of-type, :hover, 등)도 클래스와 동일한 점수를 가진다.
.list li:hover {
...;
}
header .menu li:nth-child(2) {
...;
}
- 태그 선택자: 1점
p {
color: red;
}
가상 요소
(::before, ::after, 등)는 일반적으로 태그로 취급하여 태그와 동일한 점수를 가진다.
.box::before {
...;
}
- 전체 선택자 (
*): 0점
* {
color: red;
}
- 부정 선택자 (
:not()): 0점
부정 선택자도 전체 선택자(*)와 함께 동일한 0점
이라는 점은 처음 알았다.
쉬운 예제
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
div {
border-radius: 50%;
width: 200px;
height: 200px;
}
div.hello {
/*11점*/
background-color: green;
}
.hello {
/*10점*/
background-color: red;
}
</style>
</head>
<body>
<div class="hello"></div>
</body>
</html>
점수가 더 높은 div.hello를 선택한다.
상속
부모 태그에 적용된 css 속성 중에서 자손에게도 상속되는 속성들이 있다.
이 때에도 상속의 우선순위가 존재한다.
상속된 속성의 우선순위
가장 가까운 조상에게서 물려받은 속성일수록 우선순위가 높다.
🚨이미 계산된 상속 스타일과 선택자 우선순위를 비교하려는 잘못된 경우
상속된 속성의 우선순위는 굉장히 쉽다.
하지만 가끔 이미 계산된 상속 스타일과 선택자 우선순위를 헷갈릴 수 있는 경우가 발생할 수 있다.
다음과 같은 스타일 속성이 있다고 가정했을 때 "CSS 속성"이라는 텍스트가 가질 텍스트 색상을 맞춰보자.
<div id="header">
<h1 class="title">CSS 상속</h1>
<p class="description">
태그들은 <span class="accent">CSS 속성</span>을 부모 태그에서 물려 받습니다.
</p>
</div>
body {
color: #0000bb;
}
.title {
color: #bbbb00;
}
.description {
color: #cc0000;
}
#header > .description {
color: #bb0000;
}
.accent {
color: #00cc00;
}
정답을 여기서 `#bb000`으로 생각했다면 아래 해설을 읽어햐 하고, 아니면 넘어가도 좋다.
해설
우선 `p.description 태그`(`.description` 클래스가 있는 `<p>` 태그)의 스타일을 계산해 보면 다음 순서대로 우선순위가 높다.
#header > .description {
color: #bb0000;
}
.description {
color: #cc0000;
}
그래서 `p.description`에 계산된 스타일은 아래가 된다.
/* p.description 태그의 속성 */
{
color: #bb0000;
}
이 상태(부모태그 스타일 우선순위 계산이 끝난 상태)에서 `<span>`태그에 적용되는 CSS 태그를 우선순위에 따라 정리해보면 다음과 같다.
/* "CSS 속성"이라는 글자에 직접 적용된 속성 */
.accent {
color: #00cc00;
}
/* p.description 태그에서 물려 받은 속성 */
{
color: #bb0000;
}
/* body 태그에서 물려 받은 속성 */
{
color: #0000bb;
}
여기서 주의할 점은 `description`클래스가 있는 태그에 `#header > .description` 선택자로 스타일이 지정되었기 때문에 `.accent { ... }`보다 우선순위가 높은 게 아닐까? 라고 착각할 수도 있다는 점이다.
하지만 `<span>`태그의 스타일을 계산할 때는 조상 태그들의 스타일이 이미 계산된 상태이고 최종 계산된 것을 가지고 상속받는다. 그래서 `<span class="accent">CSS 속성</span>`에 최종적으로 계산된 글자색은 `#00cc00`이다.
크롬 개발자 도구에서 확인해보면 아래와 같이 계산된 것을 확인할 수 있다.

쉽게 생각하자면, 상속 우선순위를 따져서 상속된 스타일 보다는 해당 태그를 직접적으로 가리키는 우선순위가 높은 선택자에 명시된 스타일이 우선순위가 더 높다.
유용한 사이트(명시도 계산)
선택자 명시도가 복잡할 경우 쉽게 계산할 수 있도록 도와주는 사이트가 있어서 소개한다.