CSS 선택자란
선택자는 규칙에서 중괄호 앞에 오는 부분이에요. 선언을 어떤 요소에 적용할지 정해요.
p.note { color: #2563eb; }
/* selector: p.note declaration: color: #2563eb */
기본 선택자 다섯 가지면 실제 스타일시트 대부분을 다룰 수 있어요.
한눈에 보는 선택자 종류
| 선택자 | 예시 | 일치하는 것 |
|---|---|---|
| 전체 | * | 모든 요소 |
| 타입 | p | 모든 <p> |
| 클래스 | .tip | class="tip"을 가진 요소(다른 클래스와 함께여도 돼요) |
| ID | #main-title | id="main-title"인 요소 |
| 속성 | [type="email"] | 속성이 일치하는 요소 |
| 가상 클래스 | a:hover, li:first-child | 특정 상태나 위치에 있는 요소 |
| 가상 요소 | p::first-line, .x::before | 요소의 일부분 |
| 그룹 | h1, h2, h3 | 목록 중 하나와 일치하는 모든 것 |
| 복합 | p.tip | 그 클래스도 가진 <p> |
클래스와 ID는 CSS 클래스 선택자 페이지에서 따로 다뤄요. :nth-child(), :not() 같은 가상 클래스는 가상 클래스 페이지에서 설명해요.
결합자: 자손과 자식
결합자는 HTML 트리에서의 관계로 두 선택자를 이어요. 네 가지가 있어요.
| 결합자 | 문법 | B와 일치하는 조건 |
|---|---|---|
| 자손 | A B (공백) | B가 A 안 어디에든 있을 때 |
| 자식 | A > B | B의 부모가 A일 때 |
| 인접 형제 | A + B | 같은 부모 아래에서 B가 A 바로 뒤에 올 때 |
| 일반 형제 | A ~ B | 같은 부모 아래에서 B가 A 뒤 어딘가에 올 때 |
공백과 >는 사람들이 가장 많이 헷갈리는 짝이에요. 자손 선택자는 깊이에 상관없이 닿고, 자식 선택자는 한 단계에서 멈춰요.
형제 결합자: +와 ~
형제 결합자는 앞으로만 봐요. "이전 형제" 결합자는 없지만 :has()로 표현할 수 있어요. h2:has(+ p)는 바로 뒤에 p가 오는 h2와 일치해요.
속성 선택자
대괄호는 속성과 그 값으로 일치 여부를 판단해요.
| 선택자 | 일치하는 것 |
|---|---|
[disabled] | 값과 상관없이 그 속성이 있을 때 |
[type="email"] | 값이 정확히 email일 때 |
[href^="https"] | 값이 https로 시작할 때 |
[href$=".pdf"] | 값이 .pdf로 끝날 때 |
[class*="icon"] | 값 어딘가에 icon이 있을 때 |
[lang|="en"] | 값이 en이거나 en-으로 시작할 때 |
[data-state="open" i] | 대소문자를 무시하고 정확히 같을 때 |
data-* 속성에 속성 선택자를 쓰면 클래스 이름을 새로 만들지 않고도 JavaScript가 지정한 상태를 깔끔하게 꾸밀 수 있어요.
선택자 직접 테스트하기
상자에 선택자를 입력해 보세요. 일치하는 모든 요소에 주황색 외곽선이 생기고, 아래에 개수가 표시돼요.
#demo a, ul > li, h2 ~ *, a[href^="https"], li:not(.active)를 입력해 보세요.
복합 선택자와 자손 선택자: 공백이 중요해요
p.note와 p .note는 공백 하나 차이지만 뜻이 달라요.
브라우저가 선택자를 읽는 방식
여러 규칙이 같은 요소와 일치하고 같은 속성을 지정하면 더 구체적인 선택자가 이기고, 동점이면 나중 것이 이겨요. ID 하나는 클래스 몇 개보다도 무겁고, 클래스 하나는 타입 선택자 몇 개보다도 무거워요. 전체 명시도 표는 !important 페이지에 있어요.
그룹에는 함정이 하나 있어요. 일반 목록에서 선택자 하나라도 잘못되면 규칙 전체가 버려져요. a, b:unknown { }에서는 링크조차 꾸며지지 않아요. 목록을 :is()로 감싸면 관대하게 처리돼서 :is(a, b:unknown)은 링크를 여전히 꾸며요.
자주 하는 실수
- 점이나 해시 빠뜨리기.
tip { }은class="tip"이 아니라<tip>요소를 대상으로 해요..tip으로 쓰세요. - 복합 선택자에 공백 넣기.
p .note는p.note가 아니에요. >가 손자까지 닿을 거라고 기대하기. 깊이에 상관없이 고르려면 공백을 쓰세요.- 오타 하나가 그룹 전체를 망가뜨리기.
h1, h2:hovr, h3에서는 아무것도 꾸며지지 않아요. - 지나치게 긴 선택자.
body div.wrapper ul li a는 읽기도 느리고 덮어쓰기도 어려워요. 보통은 클래스 하나면 충분해요.
자주 묻는 질문
CSS 선택자란 무엇인가요?
CSS 규칙에서 { 앞에 오는 부분으로, 선언을 어떤 요소에 적용할지 정해요. p.note { color: blue; }에서 선택자 p.note는 클래스가 note인 모든 <p>와 일치해요.
CSS 선택자에서 공백과 >는 무엇이 다른가요?
공백은 자손 결합자예요. nav a는 nav 안의 모든 링크와 깊이에 상관없이 일치해요. >는 자식 결합자예요. nav > a는 바로 위 부모가 nav인 링크와만 일치해요.
CSS에서 +는 무슨 뜻인가요?
+는 인접 형제 결합자예요. h2 + p는 같은 부모 아래에서 <h2> 바로 뒤에 오는 <p>와 일치해요. ~는 더 느슨해요. h2 ~ p는 뒤에 오는 모든 <p> 형제와 일치해요.
CSS에서 속성으로 요소를 선택하려면 어떻게 하나요?
속성을 대괄호에 넣어요. [disabled]는 그 속성이 있는 요소, [type="email"]는 값이 정확히 같은 요소, [href^="https"]는 값이 그 문자열로 시작하는 요소, [href$=".pdf"]는 그 문자열로 끝나는 요소, [class*="btn"]는 그 문자열을 포함하는 요소와 일치해요.
CSS로 부모 요소를 선택할 수 있나요?
네, :has() 가상 클래스로 할 수 있고, 최신 Chrome, Firefox, Safari에서 지원해요. li:has(> a.active)는 활성 링크를 바로 안에 가진 목록 항목과 일치해요.