본문 바로가기
웹 프로그래밍 기초

[CSS] Cascade, specificity, inheritance

by oncerun 2023. 4. 10.
반응형

 

최근 홈페이지 하나를 만들면서 가장 시간을 많이 보낸 것이 CSS인데, 분명 속성을 공식문서를 보고 적용했는데, 해당 속성이 작동하지 않는 것을 확인할 수 있습니다.

 

실제 크롬에서 개발자 도구를 통해 확인하면 취소선이 그어져있지만 이에 대한 별도의 로그가 없기 때문에 왜 적용이 안 되는 것인지 확인하기가 어려웠습니다.

 

백엔드를 주로 다루기 때문에 기본적인 Web 지식 중 하나인 CSS를 소홀히 공부한 것을 반성하고 다시 한 번 기초를 잡아보려고 합니다.

 

CSS는 Cascading Style Sheets를 의미하며, 첫 번째 단어인 Cascade를 이해하는 것은 매우 중요합니다.

우선 속성이 중복된 경우 문제는 동일한 속성의 다른 값을 동일한 요소에 적용하는 두 개의 규칙을 적용하려고 하는 경우 발생합니다.

 

Cascade와 밀접하게 관련된 Specificity 개념이 이러한 충돌이 있는 경우 적용되는 규칙을 제어하는 메커니즘으로 이 메커니즘도 이해해야 합니다.

 

여기서 중요한 것은 inheritance 개념으로 기본적으로 일부 CSS 속성은 현재 요소의 상위 요소에 설정된 값을 상속하고 일부의 경우는 상속받지 않습니다.

 

 

Cascade

 

기본적으로 Cascade는 동일한 속성을 갖는 경우 스타일 시트에서 마지막으로 정의된 규칙이 사용됩니다.

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            color: black;
        }

        h1 {
            color: blue;
        }

        .title {
            color: red;
        }
    </style>
</head>
<body>
    <h1 class="title" style="color:brown">Title</h1>
</body>

이 경우 Title의 color에 적용되는 속성은 무엇일까요?

 

 

Specificity

 

브라우저는 요소에 적용되는 속성 값을 결정하기 위해 specificity 알고리즘을 사용합니다.

 

기본적으로 선택자의 선택이 얼마나 구체적인지에 대한 척도입니다.

 

element selector는 덜 구체적입니다. 해당 유형의 모든 요소를 선택하므로 가중치가 적습니다.

 

위에서 element selector는 body, h1입니다.

 

class selector는 더 구체적으로 가중치가 높다고 판단합니다. 이는 특정 요소만 선택하기 때문입니다.

 

추가적으로 Attribute selectors와 pseudo-classes는 동일한 가중치를 갖습니다.

 

 

inheritance

 

부모 요소에 설정된 일부 CSS 속성 값은 자식 요소에 의해 상속되고 일부는 그렇지 않습니다.

<style>
        body {
            color: green;
        }

        h1 {
            color: blue;
        }

        .title {
            color: red;
        }
    </style>

<body>
    <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Error maiores tenetur debitis officiis, dolore minus
        vel quo dignissimos. Omnis facere necessitatibus possimus saepe! Quasi sint cum nesciunt ad dolorum? Pariatur?
    </p>
    <h1 class="title" style="color:brown">Title</h1>
</body>

이 경우 <p> 엘리먼트의 색상은 body로부터 상속받은 green이 됩니다.

 

다만 일부는 그렇지 않다는 것은 다음과 같습니다.

 

만약 부모 width의 크기를 50%로 설정한 경우 모든 자식들의 width 값이 부모 넓이의 50%로 설정되지 않습니다.

width, margin, padding, border와 같은 속성은 상속되는 속성이 아닙니다.

 

CSS는 이러한 상속을 제어하기 위해 5가지 특수 범용 속성 값을 제공합니다.

 

즉 모든 CSS 속성은 이러한 값을 허용하는 것입니다.

 

  • inherit : 선택한 요소에 적용되는 속성 값을 상위 요소의 속성 값과 동일하게 설정합니다.
  • initial : 선택한 요소에 적용된 속성값을 해당 속성의 초기값으로 설정합니다.
  • revert : 선택한 요소에 적용된 속성 값을 해당 속성에 적용된 기본값이 아닌 브라우저의 기본 스타일로 재설정하며 이 값은 unset과 많이 사용됩니다.
  • unset : 속성을 자연 값으로 재설정합니다. 즉 속성의 값이 자연스럽게 상속되면 inherit처럼 작동하고 그렇지 않으면 initial처럼 작동합니다.

 

브라우저가 정확히 어떤 CSS를 적용해야 하는지 파악하는 방법을 확인하기 위해 다음과 같은 요소를 더 살펴볼 것입니다.

  1. Importance
  2. Specificity
  3. Source order

Source order

Source order는 이미 위에서 확인했듯이 가중치가 모두 동일한 규칙이 두 개 이상 있는 경우 CSS에서 마지막에 오는 규칙이 적용됩니다.

즉 요소 자체에 더 가까운 규칙이 이전 규칙을 덮어쓰고 마지막 규칙이 요소의 스타일을 지정하게 됩니다.

어찌 보면 CSS 속성은 모두 default 값이 있기 때문에 이를 전부 cascade 한다고 생각할 수 있을 것 같습니다.

 

 

 

Specificity

Source order에 따르면 가중치에 따라서 CSS가 적용된다는 것을 이해했다.

이는 요소에 적용되는 여러 규칙들 중에서 가중치에 따라 1차적으로 분류되고 동일한 가중치를 가지는 규칙에는 마지막 규칙이 적용된다는 것을 의미합니다.

이를 통해 반복을 피하는 좋은 방법이 있습니다.

기본 요소의 일반 스타일을 정의한 다음, 다른 요소에 대한 class를 작성하는 것입니다.

만약 제가 CSS를 처음부터 세팅한다면 다음과 같은 과정을 거칠 것 같습니다.

  1. reset css를 통해 엘리먼트 요소에 대한 기본 속성 + 커스텀 속성을 적용합니다. 이 경우는 모든 엘리먼트를 선택하여 사용하기에 가중치가 클래스 선택, 아이디 선택에 비해 낮습니다.
  2. Layout을 작성하고 그중 공통적으로 layout에 의존하지 않고 사용될 css를 우선 작성합니다. 이는 클래스로 정의하고 필요에 따라 적용할 것입니다.

여기서 다음과 같은 의문을 해결해야 합니다. 클래스로 스타일을 적용한다면 동일 속성을 가진 여러 클래스를 하나의 엘리먼트에 적용하면 무엇이 우선되는지 확인해야 합니다.

.title {
            color: red;
        }

.title2 {
    color: aqua;
}

<h1 class="title title2">Title</h1>

Source order가 그대로 적용되는군요 aqua 속성이 적용됩니다.

따라서 클래스의 마지막에 추가된 요소를 브라우저가 적용합니다.

 

  1. 보통 이러한 경우가 많은 것 같습니다. ul 하위 여러 li들이 존재하는데, 각 il는 공통적인 클래스를 갖도록 설정한 후 이후 클래스를 추가하여 css 규칙을 덮어쓰도록 구성하면 될 것 같습니다.

MDN에 있는 우선순위 점수입니다. 아이디가 점수가 높군요.

 

이를 쉽게 파악할 수 있는 예제가 있습니다.

<div id="outer" class="container">
    <div id="inner" class="container">
        <ul>
            <li class="nav"><a href="#">One</a></li>
            <li class="nav"><a href="#">Two</a></li>
        </ul>
    </div>
</div>
  1. background에 대한 경쟁입니다.
#outer a {
 background-color: red;
}

ID selector와 요소를 선택하는 경우 다음과 같은 점수를 얻습니다.  

0101

 

 

다음은 두 개의 아이디 선택자와 요소를 선택하였습니다.

#outer #inner a {
 background-color: blue;
}

이 경우는 다음과 같은 점수를 얻게 됩니다.

0201

따라서 background-color는 blue로 선택이 될 것입니다.

  1. <a> 요소 color에 대한 경쟁입니다.
#outer div ul li a {
    color: yellow;
}

#outer div ul .nav a {
    color: white;
}

중간에 클래스에 대한 선택자가 껴있습니다. 두 개의 CSS 규칙에 대한 점수는 다음과 같습니다.

0104 vs 0113

 

color의 속성은 white로 결정됩니다.

  1. 다음은 의사요소가 있는 경우 border 속성입니다.
div div li:nth-child(2) a:hover {
    border: 10px solid black;
}

div li:nth-child(2) a:hover {
    border: 10px dashed black;
}

 

둘 다 div 요소 하위 li의 두 번째 요소에 마우스를 올렸을 때 발생하는 테두리 속성 규칙을 정의하고 있습니다.

이에 대해 점수를 측정합니다.

 

div div li:nth-child(2) a:hover 인 경우 엘리먼트 요소는 4개 의사 요소는 2개입니다.

따라서 점수는 0024입니다.

 

div li:nth-child(2) a:hover의 경우는 요소 3개와 의사요소 2개로 0023입니다.

따라서 dashed 속성이 아닌 solid 속성이 적용됩니다.

 

이러한 특징을 알게 되면 라이브러리를 사용할 때 특정 규칙을 사용할 수 있습니다.

보통 css 라이브러리들을 보면 class요소를 많이 사용합니다.

 

그래서 사용자가 커스텀한 클래스를 추가하는 경우 가중치가 밀려 적용이 안될 수도 있겠군요.

저는 css가 포함된 라이브러리를 사용할 때 커스텀하는 경우 id 선택자를 사용하겠습니다.

 

그 이유는 아이디 선택자 하나가 여러 클래스 선택자가 결합된 가중치보다 높을 가능성이 크고, 이를 역전시키기 위해 라이브러리에서 여러 클래스를 결합할 이유가 없기 때문입니다.

 

 

혹은! important를 적용할 수 있을 것 같습니다.

 

 

 

! important는 모든 계산을 무효화하는 데 사용됩니다.

이는 특정 속성과 가중치를 가장 구체적으로 만들어 일반적인 cascade 규칙을 무시하는 데 사용됩니다.

이를 가독성 부분으로 살펴보면 다른 사람이 해당 코드를 발견할 때 우선적으로 적용된다는 것을 알 수 있지만 기본적인 cascade 정상적인 작동 방식을 변경하기 때문에 반드시 필요한 경우가 아니라면 사용하지 않는 것이 좋다고 합니다.

여기까지 기본 CSS의 메커니즘을 살펴보았습니다.

CSS는 디버깅하는 것이 매우 어려운 것 같습니다. 일적으로 자주 접하지 않는다면 잊어버리기 쉽기 때문에 기본 지식만 확실히 알아두고 나머지는 검색을 통해 보충하는 방법으로 가야겠습니다.

반응형

'웹 프로그래밍 기초' 카테고리의 다른 글

Header Fixed  (0) 2023.04.17
Grid  (0) 2023.04.10
DOM (2)  (0) 2022.03.12
DOM (1)  (0) 2022.03.12
브라우저의 렌더링 과정  (0) 2022.03.11

댓글