AD JB Toolbox 01

CSS 강좌 / 상속·우선순위·캐스케이드로 최종 스타일 결정하기

CSS의 최종 스타일은 각 요소의 속성별로 적용 후보를 비교한 뒤 결정됩니다. 상속은 부모의 값을 물려받는 과정이고, 캐스케이드(cascade)는 여러 선언 중 어떤 선언을 사용할지 정하는 과정입니다. 같은 출처·중요도·레이어 조건에서는 선택자 우선순위를 비교하고, 그것도 같을 때 작성 순서를 비교하므로 “맨 아래 CSS가 항상 이긴다”는 설명은 정확하지 않습니다.

상속과 직접 지정부터 구분하기

상속은 자식 요소가 부모 요소의 값을 물려받는 것입니다. 글자색 color나 글꼴 관련 속성은 일반적으로 상속되는 반면, 테두리 border와 안쪽 여백 padding은 기본적으로 상속되지 않습니다. 모든 속성이 부모와 같아진다고 생각하면 문단에 예상하지 못한 테두리를 찾게 될 수 있습니다.

#main {
  color: purple;
  border: 1px solid purple;
}
p { color: #555; }
<main id="main">
  <h1>작은 정원</h1>
  <p>방문 안내입니다.</p>
</main>

이 두 조각만 적용한다고 가정하면 h1은 부모 main의 보라색을 물려받습니다. p에는 직접 지정한 회색이 적용됩니다. 부모의 #main이 ID 선택자라는 이유로 자식 p의 직접 지정값을 이기지는 않습니다. 서로 같은 요소에 적용되는 두 선택자의 경쟁이 아니기 때문입니다. 테두리는 main의 상자 주위에 생기며 h1과 p 각각의 테두리로 복제되지 않습니다.

상속되지 않는 속성도 border: inherit처럼 명시하면 부모의 계산된 값을 물려받을 수 있습니다. 반대로 상속 속성이라도 해당 요소에 적용되는 선언이 있으면 그 선언을 먼저 처리합니다. 어떤 속성이 상속되는지와 inherit의 의미는 MDN의 CSS 상속 설명에서 확인할 수 있습니다.

최종 선언을 판단하는 순서

처음에는 본문에 작성한 CSS, 즉 같은 작성자 출처의 일반적인 스타일을 중심으로 아래 순서를 사용하세요. 먼저 선택자가 해당 요소에 일치하고 문법·조건이 유효한지 확인합니다. 대상이 아닌 규칙이나 잘못된 값은 우선순위 계산에 넣기 전에 제외해야 합니다.

  1. 출처와 중요도, 레이어 등의 상위 조건을 확인합니다. 작성자 CSS와 사용자 CSS·브라우저 기본 스타일의 출처, !important 여부, @layer 사용 여부 등이 여기 관련됩니다. 상위 조건이 다르면 선택자의 점수만 비교해서 결정하지 않습니다.
  2. 같은 조건 안에서 선택자 우선순위를 비교합니다. 우선순위(specificity)는 선택자가 얼마나 구체적인지 비교하는 기준입니다. ID, 클래스 계열, 요소 계열을 순서대로 비교합니다.
  3. 우선순위까지 같으면 뒤에 작성된 선언을 사용합니다. 이 강의의 예제처럼 @scope 등의 추가 조건이 없는 상황에서는 최종 동률을 소스 순서로 해결합니다.
  4. 선언으로 정해지지 않은 속성은 기본값 처리 과정을 따릅니다. 상속되는 속성은 부모에게서 값을 물려받고, 그렇지 않은 속성은 초기값 등을 사용합니다.

캐스케이드는 CSS의 전체 충돌 해결 체계이고, 선택자 우선순위는 그 안의 한 기준입니다. 애니메이션·전환, 레이어, 스코프를 사용하는 고급 상황에는 추가 규칙이 있으므로 여기의 단순 예제를 전체 규칙으로 확대하지 마세요. 출처와 중요도·레이어의 관계는 W3C의 캐스케이드 정렬 규칙에 정의되어 있습니다. 아래 전체 예제에는 애니메이션·전환·@layer·@scope를 사용하지 않습니다.

선택자 우선순위는 세 열로 비교하기

이 강의의 기본 선택자는 ID 수, 클래스·속성·가상 클래스 수, 요소·가상 요소 수의 세 열로 읽을 수 있습니다. 왼쪽 열부터 비교하고, 차이가 나면 그 결과로 결정합니다. 단순히 ID=100, 클래스=10, 요소=1을 더하는 십진수 점수표로 외우지 마세요. 클래스가 많이 모였다고 ID 열을 넘어서는 방식이 아닙니다.

선택자 ID 클래스·속성·가상 클래스 요소·가상 요소 표기
p 0 0 1 0-0-1
.notice 0 1 0 0-1-0
p.notice 0 1 1 0-1-1
[required] 0 1 0 0-1-0
a:hover 0 1 1 0-1-1
p::before 0 0 2 0-0-2
#opening 1 0 0 1-0-0
#main .notice 1 1 0 1-1-0

p.notice와 .notice는 ID 열이 같고 클래스 열도 같습니다. 요소 열에서 1과 0의 차이가 나므로 p.notice가 높습니다. #opening과 p.notice는 첫 열에서 1과 0의 차이가 나므로 #opening이 높습니다. 공백, >, +, ~ 같은 관계 표기와 전체 선택자 *는 이 비교의 수를 직접 늘리지 않습니다.

p.notice { color: #087f5b; }
.notice { color: tomato; }

같은 p.notice에 두 규칙이 적용되면 뒤의 .notice보다 앞의 p.notice가 높은 우선순위를 가져 초록색이 됩니다. 순서만 뒤로 옮긴다고 결과가 바뀌지 않습니다. 반면 .notice 규칙끼리 같은 속성을 두 번 지정하면 우선순위가 같으므로 뒤의 선언이 이깁니다. 이 계산은 같은 출처·중요도·레이어 조건이라는 전제에서 사용하는 것이며, 특수한 가상 클래스에는 별도 계산 규칙이 있습니다. 자세한 예외는 MDN의 선택자 우선순위 설명을 참고하세요.

속성별로 다른 선언이 이길 수 있습니다

.notice {
  color: blue;
  padding: 12px;
  border: 1px solid #087f5b;
}
.notice {
  color: tomato;
  padding: 20px;
}

이 두 규칙만 같은 요소에 적용하면 color와 padding은 뒤의 선언을 사용하고, border는 앞 규칙의 선언이 남습니다. 뒤의 규칙에 border가 없다고 앞 규칙 전체가 사라지는 것은 아닙니다. CSS는 “규칙 블록 하나를 통째로 선택”하는 방식보다 “속성마다 값을 결정”하는 방식으로 이해해야 합니다.

예를 들어 글자색은 ID 규칙, 여백은 뒤의 클래스 규칙, 테두리는 앞의 클래스 규칙에서 올 수 있습니다. 개발자 도구에서 취소선을 볼 때도 선언 하나씩 읽으세요. color에 취소선이 있다고 같은 블록의 padding까지 적용되지 않는 것은 아닙니다.

전체 예제를 먼저 예측하고 실행하기

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>작은 정원</title>
  <style>
body { margin: 24px; font-family: sans-serif; line-height: 1.7; }
    #main { color: purple; }
    p { color: #555; }
    .notice {
      color: blue;
      padding: 12px;
      border: 1px solid #087f5b;
    }
    p.notice { color: #087f5b; }
    .notice { color: tomato; padding: 20px; }
    #opening { color: #1d4ed8; }
  </style>
</head>
<body>
<main id="main">
    <h1>작은 정원</h1>
    <p id="opening" class="notice">A: 매일 오전 9시에 문을 엽니다.</p>
    <p class="notice">B: 물병과 편한 신발을 준비하세요.</p>
    <p>C: 안내 데스크에서 문의하세요.</p>
  </main>
</body>
</html>

브라우저에서 열기 전에 A·B·C의 색과 안내문 여백을 예측해 보세요. 전체 코드를 index.html로 저장해 열면 다음 결과가 나옵니다. body의 글꼴과 줄 높이는 보기 편하게 하는 보조 설정입니다.

대상과 속성 최종 결과 결정 이유
h1의 color 보라색 purple main의 color를 상속합니다. h1에 다른 color 선언이 없습니다.
A의 color 파란색 #1d4ed8 #opening이 같은 A에 적용된 p.notice, .notice, p보다 높은 우선순위를 갖습니다.
B의 color 초록색 #087f5b p.notice가 더 뒤의 .notice보다 높은 우선순위를 갖습니다.
C의 color 회색 #555 p의 직접 지정값을 사용하며 부모의 보라색을 그대로 상속하지 않습니다.
A·B의 padding 20px 두 .notice 선언의 우선순위가 같아 뒤의 padding이 이깁니다.
A·B의 border 1px 초록색 실선 뒤 규칙에 border 선언이 없으므로 앞의 유효한 선언이 남습니다.

Computed에서 확인하면 A의 color는 rgb(29, 78, 216), B의 color는 rgb(8, 127, 91), C의 color는 rgb(85, 85, 85)로 표시될 수 있습니다. 색상 표기가 달라도 같은 값을 가리킵니다. padding은 각 방향이 20px인지, border는 두께와 선 모양이 그대로인지 함께 확인하세요.

important와 인라인 스타일의 비교 범위

!important는 선언의 중요도를 바꾸는 표기입니다. 선택자의 세 열에 큰 숫자를 더하는 기능이 아닙니다. 같은 작성자 출처에서는 important 선언이 일반 선언보다 우선하므로 아래 규칙을 전체 예제 끝에 추가하면 A와 B의 색이 모두 토마토색으로 바뀝니다. ID의 일반 color 선언도 이 important 선언보다 우선하지 않습니다.

.notice { color: tomato !important; }

이 결과가 important가 언제나 모든 스타일보다 강하다는 뜻은 아닙니다. 사용자 important 스타일이나 전환 중의 값 등은 별도의 순서를 따릅니다. important 선언끼리도 출처와 레이어 등을 먼저 확인해야 합니다. 이 실습에서는 important를 관찰한 뒤 추가한 규칙을 지우세요. 보통은 선택 범위와 구조를 먼저 정리하는 편이 유지보수에 좋습니다.

<p class="notice" style="color: purple;">B: 준비물 안내</p>

important 규칙을 지운 원래 예제에서 B에 위처럼 인라인 color를 넣으면 일반 스타일시트 규칙보다 우선하여 B가 보라색이 됩니다. 인라인 스타일은 위 표의 기본 선택자 세 열과 별도로 취급합니다. 다시 일반 클래스 규칙에 important를 넣으면 인라인의 일반 color보다 우선할 수 있습니다. 따라서 “인라인이면 무조건 가장 강하다”도 조건이 빠진 설명입니다.

충돌을 해결하는 실습과 확인 순서

  1. 원본 전체 예제에서 p.notice 규칙을 맨 아래로 옮깁니다. B는 여전히 초록색이고 A는 ID의 파란색을 유지하는지 확인합니다. 높은 우선순위가 있는 상태에서는 순서 변경만으로 뒤집히지 않습니다.
  2. 그 다음 p.notice 선택자만 .notice로 바꿔 가장 아래에 둡니다. B의 색은 마지막 .notice가 지정한 초록색을 사용합니다. 같은 선택자가 되었기 때문에 이제 순서가 결정 기준입니다. 확인 후 원본을 복원합니다.
  3. A의 id="opening"만 제거합니다. A도 B와 같은 초록색이 되는지 봅니다. 부모 main의 ID는 그대로 있어도 A에 직접 지정된 초록색을 이기지 않습니다. 확인 후 ID를 복원합니다.
  4. 별도 단계로 위 important와 인라인 예제를 하나씩 적용해 비교합니다. 이전 실습 규칙을 남겨 두지 말고 원본으로 돌아간 뒤 다음 조건을 넣습니다.

결과가 예상과 다르면 개발자 도구에서 Styles와 Computed를 확인하세요. 대상 요소를 정확히 선택하고, 해당 속성의 선언을 찾고, 중요도와 선택자·순서를 비교한 뒤 최종 값을 확인합니다. 원인을 확인하지 않고 ID나 important를 계속 추가하면 당장의 색은 바뀌어도 다음 수정은 더 어려워질 수 있습니다.

같은 카테고리의 다른 글
CSS / Tutorial / ul, ol 가운데 정렬하는 방법

CSS / Tutorial / ul, ol 가운데 정렬하는 방법

목록 자체가 아니라 목록 안의 내용만 가운데 정렬할 때는 text-align 속성을 사용합니다. 목록 요소 자체를 가운데 정렬할 때는 margin 속성을 사용합니다. 만약 요소의 내용에 맞게 자동으로 크기가 정해지게 하고 싶으면 display 속성을 사용합니다.

CSS / Tutorial / 마우스 호버 효과 / 텍스트 나오게 하는 방법

CSS / Tutorial / 마우스 호버 효과 / 텍스트 나오게 하는 방법

CSS로 특정 요소에 마우스를 올렸을 때 보이지 않던 특정 요소가 보이게 할 수 있습니다. 아래는 문단에 마우스를 올렸을 때 div 요소가 나오게 하는 예제입니다. div 요소 안에 텍스트가 있지만, 텍스트가 아닌 이미지 등 다른 것도 가능합니다.

CSS / Tutorial / placeholder의 색, 글자 모양 등 꾸미는 방법

CSS / Tutorial / placeholder의 색, 글자 모양 등 꾸미는 방법

placeholder는 HTML5에서 새로 나온 속성으로 input 요소나 textarea 요소에 안내문을 넣을 수 있습니다. 기본 모양은 회색의 글자로, 배경색이 하얀색 또는 밝은 색이면 보기에 괜찮습니다. 하지만 배경색이 어두운 색이거나 화려한 색이면 회색 글자가 어울리지 않을 수 있습니다. placeholder는 ::placeholder 선택자로 선택하여 꾸밀 수 있습니다.

CSS 강좌 / 브라우저 개발자 도구로 CSS 확인하고 수정하기

CSS 강좌 / 브라우저 개발자 도구로 CSS 확인하고 수정하기

브라우저 개발자 도구에서 안내 문단을 선택하고, Styles의 선언과 Computed의 최종 값을 확인합니다. 색상 변경·선언 끄기·원본 저장 실습과 적용되지 않는 CSS의 원인별 점검 방법을 제공합니다.

CSS / Tutorial / 마우스 호버 효과 / 서서히 길어지는 선 만드는 방법

CSS / Tutorial / 마우스 호버 효과 / 서서히 길어지는 선 만드는 방법

마우스를 올리면 선이 그려지는 효과를 만들어봅니다. 다음과 같이 사각형을 만듭니다. :before를 이용하여 선이 시작하는 위치를 정합니다. position 속성으로 선 위에 선을 그릴 수 있도록 설정합니다.

CSS 강좌 / 기본 선택자 - 요소, 클래스, ID, 속성

CSS 강좌 / 기본 선택자 - 요소, 클래스, ID, 속성

요소·클래스·ID·속성 선택자를 같은 HTML에 적용해 대상과 결과를 비교합니다. 복합 클래스, 공백으로 구분한 속성값, 필수 입력칸을 포함한 전체 예제와 선택자 수정 실습을 제공합니다.

CSS 강좌 / ::before와 ::after로 가상 요소 꾸미기

CSS 강좌 / ::before와 ::after로 가상 요소 꾸미기

::before와 ::after로 HTML을 늘리지 않고 장식용 점과 선을 추가합니다. content·display·currentColor의 역할, 실제 적용 전후 화면, 전체 코드와 가상 요소가 안 보일 때의 점검 방법을 설명합니다.

CSS Tutorial / !important

CSS Tutorial / !important

CSS에서 !important는 특정 스타일 규칙이 다른 모든 스타일 규칙보다 우선 적용되도록 강제하는 데 사용됩니다. 이 키워드는 일반적인 스타일 우선 순위를 무시하고, 해당 스타일이 다른 어떤 스타일보다도 높은 우선순위를 가지도록 합니다.

CSS / Tutorial / 상속(inheritance)

CSS / Tutorial / 상속(inheritance)

CSS 속성은 상속하는 속성과 상속하지 않는 속성이 있습니다. 상속하는 속성은 자식 요소에 영향을 미칩니다. 상속하지 않는 속성은 자식 요소에 영향을 미치지 않습니다.

CSS / Tutorial / 양쪽 배분(균등 분할) 정렬 방법

CSS / Tutorial / 양쪽 배분(균등 분할) 정렬 방법

문단 정렬을 양끝으로 꽉차게 하는 경우가 있습니다. 한글에서는 배분 정렬, 워드에서는 균등 분할이라고 합니다. 일반적인 문단에서는 거의 사용하지 않고, 표에서 제목을 넣을 때 많이 사용합니다.