CSS 선택자(Selector)와 우선 순위

2011. 4. 3. 02:04IT/Tistory Tips

선택자란 CSS에서 스타일을 적용할 대상을 정의하는 기능을 한다. CSS의 세부 스타일 적용에 대해 알고 있어도 선택자를 알지 못하면 내가 원하는 부분에 스타일을 적용할 수 없다. 그러나 많이 사용되는 몇 가지만 기억하면 간단하게 사용할 수 있다. 기본적인 스타일 지정 방법은 다음과 같다.

[태그나 class, id 이름=선택자] {속성:값}

1. 선택자 종류

선택자는 크게 다음과 같이 분류할 수 있다.

선택자(selector)
  1. 인라인 (style=" ")
    태그에 직접 style=" "로 스타일을 지정한다. CSS에 따로 스타일을 지정할 필요가 없다.
  2. id (id="ex1")
    태그에 지정한 id를 선택자로 사용한다. id 앞에 샾-우물정-(#)을 추가한다. 예) #ex1
  3. class (class="ex2")
    태그에 지정한 class를 선택자로 사용한다. class 앞에 마침표(.)를 추가한다. 예) .ex2
  4. 하위 선택자 (div ul li)
    태그 요소 이름을 종속 관계에 따라 순차적으로 사용한다. div ul li { }는 div에 속한 ul 내부의 li에 해당 스타일을 적용한다는 의미다. '>', '+'로 대상을 한정할 수 있다.
  5. 타입 선택자 (p, div)
    태그 요소 이름 자체를 선택자로 사용한다. 여러 개 나열할 경우 쉼표(,)로 구분한다.
  6. 공통 선택자 (*)
    모든 요소를 선택한다.
  7. 가상 클래스 (p:first-letter)
    미리 정해진 가상 클래스를 요소 뒤에 덧붙여 특수한 상황에 적용한다.
  8. 특성 (target, title)
    태그 요소에 사용하는 특성을 선택자로 사용한다.

W3School의 선택자 분류표를 살펴보면 모든 종류의 선택자에 대해 쉽게 알 수 있다.

* 출처 : W3School (http://www.w3schools.com/css/css_reference.asp)
선택자예 설명CSS
.class .introclass="intro"인 모든 요소를 선택1
#id #firstnameid="firstname"인 모든 요소를 선택1
* *모든 요소를 선택2
element p<p> 요소를 모두 선택1
element,element div,p모든 <div> 요소와 <p> 요소를 선택1
element element div p<div> 요소 안에 있는 모든 <p> 요소를 선택1
element>element div>p부모(상위) 요소가 <div>인 모든 <p> 요소를 선택2
element+element div+p<div> 요소 바로 뒤에 있는 모든 <p> 요소를 선택2
[attribute] [target]target 특성이 포함된 모든 요소를 선택2
[attribute=value] [target=_blank]target="_blank"가 포함된 모든 요소를 선택2
[attribute~=value] [title~=flower]"flower"란 단어가 포함된 title 특성 값을 갖는 모든 요소를 선택2
[attribute|=language] [lang|=en]"en"으로 시작하는 lang 특성 값을 갖는 모든 요소를 선택2
:link a:link방문하지 않은 모든 링크 선택1
:visited a:visited이미 방문한 모든 링크 선택1
:active a:active활성화 된(현재 클릭한 상태의) 모든 링크 선택1
:hover a:hover마우스 커서가 올라가 있는 모든 링크 선택1
:focus input:focus현재 선택된 input 요소 선택2
:first-letter p:first-letter모든 <p> 요소의 첫 번째 문자 선택1
:first-line p:first-line모든 <p> 요소의 첫 번째 줄 선택1
:first-child p:first-child부모 항목의 첫 번째 자식 항목인 모든 <p> 요소 선택2
:before p:before모든 <p> 요소 앞에 내용 삽입2
:after p:after모든 <p> 요소 뒤에 내용 삽입2
:lang(language) p:lang(it)lang 속성 값이 "it"로 시작하는 모든 <p> 요소 선택2

class는 요소에 지정된 class 값으로 원하는 요소를 선택하고 CSS에서 지정할 땐 class 앞에 마침표(.)를 추가한다. HTML 문서에 <div class="div_ex1">란 부분이 있고 CSS에 .div_ex1{width:85%}라고 지정되어 있다면 class가 div_ex1이라고 정의된 부분을 HTML 문서에서 선택한 다음 width:85%란 스타일을 적용한다. 만약 HTML 문서에 <div class="div_ex1"><table class="div_ex1">가 있다면 div와 table 모두에 width:85%란 스타일이 적용된다.

이때 class가 같은 요소 중 특정 요소에만 스타일을 적용하고 싶다면, 즉, div_ex1이란 class를 가진 div에만 또는 table에만 스타일을 적용하고 싶다면 div.div_ex1{width:85%}라고 지정하든가 table.div_ex1{width:85%}라고 지정한다.

id는 요소에 지정된 id 값으로 원하는 요소를 선택하고 CSS에서 지정할 땐 id 앞에 샵-우물정(#)을 추가한다. HTML 문서에 <div class="div_ex1" id="main_ex1">이란 부분이 있고 CSS에 #main_ex1{padding:15px 0 10px}이라고 지정되어 있다면 id가 main_ex1이라고 정의된 부분을 HTML 문서에서 선택한 다음 padding:15px 0 10px이란 스타일을 적용한다. 앞에서와 마찬가지로 id가 같은 요소가 여러개 있다면 모든 요소에 스타일이 적용되고 특정 요소에만 스타일을 적용하려면 역시 마찬가지로 div#main_ex1{padding:15px 0 10px}처럼 스타일을 지정한다.

*은 모든 요소에 일괄적으로 스타일을 적용한다. CSS 처음에 *{margin:0;padding:0}이라고 지정하면 스타일 지정에 앞서 모든 요소의 바깥 여백(margin)과 안쪽 여백(padding) 값이 초기화된다. 또 요소를 지정하지 않은 class나 id 앞엔 항상 *이 생략되어 있다. 예를 들어, 앞에서 이야기한 .div_ex1{width:85%}란 스타일이 있다고 하면 사실, 이 부분은 *.div_ex1{width:85%}인데 여기서 *을 생략한 것과 같다.

요소(HTML 문서의 태그)는 특정 요소 전체를 선택한다. CSS에 p{line-height:180%}라고 지정하면 HTML 문서의 모든 p 요소는 line-height:180%의 스타일을 갖는다. 여러 요소에 일괄적으로 같은 스타일을 적용할 땐 각 요소를 쉼표(,)로 구분한다. p,span,li{line-height:180%}라고 지정하면 HTML 문서의 모든 p, span, li 요소에 line-height:180%이란 스타일이 적용된다. 요소 사이에 >를 삽입하면 포함 관계를 나타낼 수 있다. div>p{line-height:180%}라고 지정하면 p 요소 중 부모 요소가 div인 항목에만 line-height:180%이란 스타일이 적용된다. 요소 사이에 +가 있다면 앞의 요소와 붙어 있는 뒤의 요소에만 스타일이 적용된다. div+p{line-height:180%}라고 지정하면 div 바로 뒤에 붙어있는 p 요소에만 스타일이 적용된다.

한 요소에 class를 여러 개 정의할 수도 있다. class 이름 사이에 공백을 삽입하면 된다. class="className1 className2"와 같은 형식이다. 이땐 두 class에 따로 스타일을 적용할 수 있다. 예를 들어 HTML 문서에 <p class="css_ex1">Sample Text 2</p> <p class="css_ex1 css_ex2">Sample Text 3</p>이라는 부분이 있을 때 class="css_ex1"에 공통의 스타일을 지정하지만, Sample Text 3에 추가적인 속성을 지정하고 싶다면 class="css_ex1 css_ex2"처럼 class를 두 개 지정하고 .css_ex1으로 공통 스타일을, .css_ex2로 추가적인 스타일을 지정한다. 선택자 우선순위를 높이기 위해서 p.css_ex1.css_ex2 처럼 선택자에 class를 중복해서 지정할 수도 있다. 선택자 우선순위는 아래에 자세히 설명할 것이다.

아래의 예를 참고하면 요소>요소, 요소+요소가 어떻게 적용되는지 확인할 수 있다.

<예제 1>
<html>
<head>
<style type="text/css">
hr+p{color:red;font-size:28px}
div>p{color:blue;font-size:28px}
hr{width:100%;height:1px;background:#666;;border:1px solid #666}
</style>
</head>
<body>
<p>ex1</p>
<div>
<p>ex2</p>
<table><tr><td>ex3</td></tr></table>
<p>ex4</p>
</div>
<hr />
<p>ex5</p>
<p>ex6</p>
</body>
</html>

ex1

ex2

ex3

ex4


ex5

ex6


요소를 나열할 때 요소 사이를 띄우면 포함 관계를 나타낸다. div ol li{list-style:lower-greek}이라고 지정하면 div 요소 영역 안의 ol 요소 내부의 li 항목에 list-style:lower-greek이 적용된다. div, ol, li 사이에 다른 태그가 있어도 포함 관계만 유지된다면 스타일이 적용된다. 예를 들어 div 안에 table이 있고 그 안에 ol, li가 있어도 list-style:lower-greek이란 스타일은 여전히 적용된다.

특성(attribute)은 요소처럼 적용할 수 있다. HTML 문서에 <a href="http://circlash.tistory.com" target="_blank" title="circlash 블로그 바로 가기">circlash 블로그</a>라는 부분이 있을 때 CSS에 [target]{text-decoration:underline}이라고 지정하면 링크 부분에 target이라는 특성이 있으므로 'circlash 블로그'라는 링크 아래에 밑줄 스타일이 적용된다. [title~=circlash]{color:red}라고 지정하면 역시 링크 title 특성 값 중에 circlash라는 단어가 있으므로 'circlash 블로그'라는 링크 글씨 색이 빨간색으로 바뀐다.

가상 클래스(pseudo-class)는 요소의 특정 부분에만 스타일을 적용할 때 사용한다. 가장 흔히 볼 수 있는 것이 :link, :visited, :active, :hover, :focus다. 특정 주소로 링크를 거는 a라는 요소에 스타일을 부여할 때 a:link,a:visited{color:red} a:hover{color:blue}라고 지정하면 평소의 링크나 방문한 링크는 빨간색으로, 링크 위에 마우스 커서를 올렸을 땐 파란색으로 표시된다. 다른 가상 클래스 역시 비슷하게 사용할 수 있다.


2. 선택자 우선순위

일반적인 생각과 달리 스타일 시트는 여러 개가 존재한다. CSS 파일이 여러개란 의미가 아니다. 웹브라우저 자체는 기본 스타일이 지정되어 있고 웹브라우저 사용자는 여기에 자신이 사용할 스타일을 따로 지정한다. 게다가 웹사이트 제작자 역시 자신의 페이지를 표시할 스타일을 따로 지정한다. 또 이미 CSS 파일에 스타일이 지정되어 있어도 필요에 따라서 인라인 스타일이나 내부 스타일 시트로 따로 스타일을 적용하기도 한다. 따라서 각 스타일 및 선택자의 우선 순위를 알아야 내가 원하는 스타일을 정확히 적용할 수 있다.

먼저 스타일 시트의 우선 순위는 다음과 같다. 1이 낮고 5가 높다.

  1. User Agent 선언 - 브라우저 자체의 선언
  2. 사용자 선언 - 일반 : 사용자 선언 (중요도: 보통)
  3. 제작자 선언 - 일반 : 제작자 선언 (중요도: 보통)
  4. 제작자 선언 - 중요 : 제작자 선언 (중요도: 높음)
  5. 사용자 선언 - 중요 : 사용자 선언 (중요도: 높음)

여기서 User Agent 선언, 사용자 일반 선언, 사용자 중요 선언은 생각하지 않아도 된다. User Agent 선언, 사용자 일반 선언은 어차피 제작자 일반 선언이 이긴다. 또 사용자 중요 선언은 어떤 스타일 시트도 이길 수 없다. 그러니 제작자 일반 선언과 제작자 중요 선언만 생각하자.

그런데 일반 선언은 뭐고 중요 선언은 뭘까? 일반 선언은 그냥 CSS에 입력된 내용이다. 끝. 중요 선언은 속성 값 뒤에 !important라고 추가한 것이다. 끝. 간단하다. 선택자 우선순위를 정확히 알 순 없는데 내가 원하는 스타일이 적용되지 않을 때 !important로 중요 선언을 하면 우선순위가 급상승해서 바로 적용된다.

/* 사용자 스타일 시트 */
p { text-indent: 1em ! important }
p { font-style: italic ! important }
p { font-size: 18pt }

/* 제작자 스타일 시트 */
p { text-indent: 1.5em !important }
p { font: normal 12pt sans-serif !important }
p { font-size: 24pt }

위 표는 W3C에 제시된 !important에 관한 우선순위다. 첫 번째 text-indent 속성은 !important가 선언되어 있으므로 level 5인 사용자 스타일 시트가 이긴다. 두 번째 font 속성 역시 사용자 스타일 시트가 이긴다. 그러나 세 번째 font-size는 !important 선언이 없으므로 제작자의 두 번째 font 속성이 사용자의 세 번째 font-size 속성을 이긴다. 제작자의 세 번째 font-size 속성 역시 !important 선언이 없으므로 제작자의 두 번째 font 속성이 이긴다. 결국 정리하면 사용자의 웹브라우저에 표시되는 p 요소의 스타일은 p { text-indent:1em; font: italic 12pt sans-serif }가 될 것이다.

중요 선언에 대해선 일단 이 정도만 하고 실제 선택자 우선순위를 살펴보자.

* {} /* a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0 */ li {} /* a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1 */ li:first-line {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */ ul li {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */ ul ol+li {} /* a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3 */ h1 + *[rel=up] {} /* a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1 */ ul ol li.red {} /* a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3 */ li.red.level {} /* a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1 */ #x34y {} /* a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0 */ style="" /* a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0 */

* 출처 : W3C (http://www.w3.org/TR/CSS21/cascade.html#specificity)

위의 표가 바로 선택자 우선순위다. 표에서 a > b > c > d의 순으로 우선순위가 적용된다. 은메달이 아무리 많아도 금메달을 이길 수 없는 것처럼 b가 아무리 높아도 a를 이길 수 없다. style=""로 지정하는 인라인 스타일이 a로 우선순위가 가장 높고 그다음은 id로 b다. class와 가상클래스는 c, 일반 요소(태그) 및 가상요소는 d다. 주의할 것은 규모가 작아질수록(세부 항목에 대해 정의할수록) 우선순위가 높다는 사실이다. HTML 문서에 <li class="red level"> </li>라고 지정되어 있을 때 li.red.level처럼 li라는 요소에 red, level이라는 두 개의 class를 지정하면 c가 2점, d가 1점이다. 반면, ul ol li.red처럼 ul 요소 안의 ol 요소 내부의 li라는 요소에 red란 class가 지정되었을 땐 ul, ol, li로 d가 3점이지만, class는 red 하나이므로 c는 1점이다. 따라서 li.red.level과 ul ol li.red에 서로 다른 스타일 속성이 지정되어 있을 땐 li.red.level에 적용된 스타일을 사용한다. 만약 여기에 li.red .blue란 스타일이 정의되어 있다면 이 스타일의 선택자가 더 작은 범위를 제한하므로 red란 class의 li 요소 하위의 blue란 class를 갖는 특정 요소엔 li.red .blue에 정의된 스타일이, 그 외의 li.red.level 요소엔 li.red.level에 정의된 스타일이 적용된다.

  • 프로필사진
    Favicon of https://enarastudent.tistory.com BlogIcon 이나라학생2013.01.19 23:59 신고

    잘봤습니다.

    근데 명세에는 가상클래스는 c라고 나와있는데

    내부 내용 수정좀 하셔야 할 것 같네요.

    • 프로필사진
      Favicon of https://circlash.tistory.com BlogIcon circlash2013.01.27 14:33 신고

      앗, 가상 클래스는 c이고 가상 요소가 d군요. 감사합니다. 수정하겠습니다~

  • 프로필사진
    Favicon of http://codeflowblog.tistory.com BlogIcon Codeflow2013.07.23 16:18 신고

    안녕하세요. css 중요도에 관해 정리하신 내용을 혹시 저희 사이트 (codeflow.co.kr)에 옮겨적어도 좋을지 허락해 주실수 있는지요?
    저희 사이트에 대해 간단히 말씀드리자면 개발 관련 질문/답변/번역 게시판입니다. 현재 오픈한지 얼마 안되어서 여러 topic에관한 tutorial형식의 글을 작성중에 있습니다. 참고할 만한 글을 찾던중 본문글이 매우 정리가 잘되어 있어서 저희 게시판에서 공유를 할수 있으면 좋겠다는 생각이 됩니다. 게시판 포맷 때문에 불가피하게 편집되는 부분이 있을수 있으나 가급적 원글을 훼손하지 않고, 출처인 이곳의 링크도 반드시 포함하겠습니다.

    • 프로필사진
      Favicon of https://circlash.tistory.com BlogIcon circlash2013.07.23 17:30 신고

      네, 상관 없습니다. 제 블로그의 모든 게시물은 CC BY-NC-SA 3.0 라이선스를 따르므로, http://creativecommons.org/licenses/by-nc-sa/3.0/deed.ko 앞의 주소에 나온 내용을 지켜주시면 얼마든지 사용하셔도 됩니다^^