CSS에서 상당히 중요한 선택자 구체성이 나왔다. 스타일링을 하다보면 CSS 파일에 작성한 코드가 300줄은 기본으로 넘긴다. 이 300줄이 넘는 코드를, 여러 개의 하위 결합자를 사용하여 작성하다보면 내가 작성한 코드가 맘처럼 작동하지 않을 때가 있다.. 그때 우선으로 살펴봐야 할 아주 중요한 개념이라고 할 수 있다.
Selector Specificity
은 가장 관련성이 높은 속성 값을 적용하기 위해 브라우저가 사용하는 알고리즘이라고 할 수 있다. 쉽게 말하면, 선언된 CSS 선택자에 값을 매겨 가장 우선으로 적용될 선택자를 골라서 적용시키는 과정이다.
Selector Specificity는 VS코드나 크롬 개발자 도구를 통해 확인할 수 있다.
Selector Specificity
이라는 항목을 확인할 수 있고 그 옆에 (0, 2, 2) 라는 값이 보인다. 이 괄호 안에 있는 값이 가장 높은 선택자에 적힌 프로퍼티와 값이 적용된다.그래서 그게 뭐라는거냐 ~ 하는 마음이 들 수 있다. (ㅎㅎ) 이제 천천히 설명을 해보겠다 ! Selector Specificity에 사용되는 CSS의 선택자는 크게 3가지로 나뉜다. 아래의 예시를 살펴보면 #wrap .contents .skill ul
의 Selector Specificity는 (1, 2, 1)이다.
#wrap .contents .skill ul { ... } /* (1, 2, 1) */
괄호 안 세가지의 숫자 중 첫번째 숫자
는, 아이디 셀렉터의 개수를 의미한다. 선언된 선택자 내에 아이디(#) 선택자가 몇 개가 있는지 확인한다. 두번째, 세번째 숫자가 몇 만이 되든 아이디 선택자가 1개라도 있으면 이긴다. 쉽게 이해하기 위해서 금메달이라고 생각하면 좋다. 은메달, 동메달을 1000개 획득해도 금메달 1개가 이기는 것과 비슷하다.
두번째 숫자
는 클래스 셀렉터, 속성 셀렉터, 가상 클래스의 개수를 의미한다. 여기서 속성 셀렉터는 [href="/"]
등 마크업 요소에서 사용된 특정 속성이 있는 요소를 지정할 수 있는 클래스이다. 가상 클래스는 첫번째 요소를 가리키는 :first-child
, 요소를 호버했을 때의 상태를 가리키는 :hover
, 괄호 내에 작성된 것을 부정하는 :not()
등의 클래스를 의미한다. 위의 세가지 선택자 및 클래스는 각 은메달 1점을 획득한다고 할 수 있다.
세번째 숫자
는 타입 셀렉터의 개수를 의미한다. 타입 셀렉터는 HTML에서 태그 이름이다. 위에서 말한 것과 동일한 비유로 타입 셀렉터는 동메달에 비유할 수 있다.
이와 별개로, 0점을 의미하는 평화주의자 Universal Selector(*)도 존재한다.
선언된 CSS 선택자는 위의 알고리즘을 가지고 적용될 선택자의 가중치를 계산한다. Selector Specificity 값이 같다면, 가장 하단에 작성된 선택자가 적용된다. 아래 예시를 통해 감을 잡아보자 !
div { color: red; } /* (0,0,1) */
div { color: black; } /* (0,0,1) */
/* Selector Specificity이 같으므로 하단에 작성된 black 적용 */
div.wrap { color: red; } /* (0,1,1) */
div { color: black; } /* (0,0,1) */
/* red 적용 */
div.wrap.wrap { color: red; } /* (0,2,1) */
div { color: black; } /* (0,0,1) */
/* red 적용 (동일한 클래스를 두 번 이상 작성 할 수 있음) */
#div.wrap { color: red; } /* (1,1,0) */
div.wrap.wrap.wrap.wrap.wrap { color: black; } /* (0,5,1) */
div.wrap:hover { color: red; } /* (0,2,1) */
div.wrap.black { color: black; } /* (0,2,1) */
/* hover시에도 black 적용 */
위의 Selector Specificity을 결정하는 3가지의 경우를 살펴보았다. ID selector 하나면 모든 클래스와 타입 셀렉터를 이길 수 있다. 그럼 아이디 선택자를 이길 수 있는 방법은 없는걸까? 있다 ~!
Inline Style
이란, CSS 파일 또는 <style>
요소 내에 작성된 CSS 코드가 아니라, HTML의 요소 내 속성으로 스타일을 작성하는 방법이다. 아래 예시와 같이 작성할 수 있다.
<!-- 적용 -->
<section id="section" class="section" style="color: red;"> ... </section>
<style>
/* (1,4,1) */
section#section.section.section.section.section { color: black; }
</style>
이렇게 작성된 Inline Style
은 위에서 Selector Specificity에 적용되던 3가지의 경우를 모두 제치고 우선으로 적용된다. 아무리 아이디와 많은 클래스 선택자를 사용하더라도 인라인으로 적용된 스타일이 적용된다. 위의 예시에선 결국 컬러는 red가 적용될 것이다.
실무에서 일을 하다보면 어쩔 수 없이 JacaScript로 스타일을 설정하기도 한다. 그땐 인라인으로 스타일이 부여되는데 ... (물론 그 자스 코드를 수정하는 것이 제일 좋지만) 백엔드 개발자가 뿌린 스타일을 우린 평생 이길 수 없는걸까 ...?
그때 바로 !important
를 사용할 수 있다. 해당 명령어는 프로퍼티에 부여된 값 뒤에 한 칸 띄어쓰기 후 사용할 수 있다. !important
는 인라인 스타일을 재정의 할 수 있는 좋은 방법이다.
!important
를 동일하게 사용한 여러 개의 선언문이 있을 경우, 마찬가지로 Selector Specificity를 통해 적용됨
<section id="section" class="section" style="color: red;"> ... </section>
<style>
/* 적용 */
section#section.section { color: black !important; }
</style>
가장 막강한 파워를 지닌 만큼, !important
는 남발해선 안된다. (절대)
내가 지정하지 않은 클래스와 아이디가 난무해있던 워드프레스 프로젝트의 유지보수를 할 때 ... 팀 내 누군가 쉽게 코드를 작성하기 위해서 !important
를 여기 저기 사용했었다. 그 사람이 자리를 비워 내가 해당 코드를 수정할 때 범벅이 된 !important
를 이기기 위해서 나도 !important
를 사용해야만 했다. 결국 거의 모든 값에 !important
가 붙어있었다. ;; ㅎㅎ ;; !important
는 최대한 지양하자 !
캐스케이드
라는 뜻은 폭포가 되어 떨어지다, 계단식, 위에서 아래로 떨어지는 등의 의미를 가지고 있다. CSS
는 Cascading Style Sheets의 약자다. 그만큼 캐스 케이딩이 CSS에서 의미하는 바는 아주 중요하다. 과연 뭐길래 ~
캐스케이딩
은 결과물을 산출하는 스타일링에 적용되는 일련의 과정, 모든 알고리즘을 의미한다. CSS 속성 값 선언은 문서가 렌더링되는 방식을 정의한다. 여러 선언 중에서, 동일한 요소나 속성의 조합에 대해 서로 다른 값을 설정할 수 있지만 모든 CSS 속성에는 하나의 값만 적용할 수 있다. 캐스케이드 는 이러한 충돌을 해결하는 방법을 정의한다.
결국 적용될 속성을 결정하는 방식인데, 여기에는 위에서 살펴봤던 Selector Specificity, 상속 등이 영향을 미친다.
line-height
는 텍스트의 줄간격을 의미한다. line-height는 텍스트가 한 줄을 넘지 않을 경우, 수직 중앙 정렬을 위해 자주 사용된다. (두 줄이 넘어가면? flex ~)
여기 font-size: 100px
의 텍스트가 있다. 주의해야할 점은 높이다. 분명 폰트 사이즈가 100px이고 패딩을 부여하지 않았음에도 높이가 160px로 잡힌다. 60px은 대체 어디서 온걸까? 바로! line-height이다. font-size * line-height = 컨텐츠 높이인데, 1.6만큼의 line-height가 부여되어 있던 것이다.
line-height
의 초기값은 normal
이다. 이것은 1.4 또는 1.6과 같은 특정 숫자를 의미하지 않는다. 폰트를 제작한 사람이 각 폰트에 설정한 값이 자동으로 적용된다.
line-height
를 설정하면, 텍스트 기준 상하 여백이 주어진다. 여백이 주어지는 식을 세워보면 다음과 같다.
물론 line-height가 아닌 padding으로도 수직 중앙 정렬이 가능하다. 하지만 폰트 사이즈를 고려하여 수직 중앙 정렬을 하는 것에는 에너지가 많이 소요되고, 정확도도 떨어진다. line-height는 아예 컨텐츠 높이에서 폰트 사이즈를 뺀 값을 여백으로 추가하기 때문에 원하는 높이값을 정확히 맞출 수 있다.
멋사는 체력 싸움인디 벌써 넘 피곤하면 우짠디 ~ 연말 약속 다 취소 통보 해줄 매니저를 구해야겠다 ㅎ
넘 졸리니 사담도 짧게 끝 .. ~