가상 클래스란
가상 클래스는 콜론 뒤에 오는 키워드로, 문서 안의 위치나 상태로 요소를 골라요. 일반 선택자에 붙여 써요. li:first-child, input:focus, a:hover처럼요.
링크와 마우스의 상태 가상 클래스(:hover, :active, :visited)는 CSS hover 페이지에서 따로 다뤄요.
:nth-child()와 an+b 공식
:nth-child()는 숫자, 키워드, 또는 an+b 공식을 받아요. 브라우저는 n = 0, 1, 2, ...를 차례로 넣어 보고 공식이 만드는 모든 위치와 일치시켜요(위치는 1부터 시작해요).
| 공식 | 일치하는 위치 | 뜻 |
|---|---|---|
3 | 3 | 세 번째 자식 |
odd 또는 2n+1 | 1, 3, 5, ... | 홀수 행 |
even 또는 2n | 2, 4, 6, ... | 짝수 행 |
3n | 3, 6, 9, ... | 세 개마다 하나 |
n+4 | 4, 5, 6, ... | 네 번째부터 |
-n+3 | 1, 2, 3 | 처음 세 개 |
3n+1 | 1, 4, 7, ... | 첫 번째부터 세 개마다 하나 |
공식을 입력하고 어떤 항목이 일치하는지 보세요.
odd, even, 4, n+7, -n+5, 2n+3을 입력해 보세요. 잘못된 공식은 아무것도 고르지 않아요.
끝에서부터 세는 짝은 :nth-last-child()예요. li:nth-last-child(-n+2)는 마지막 두 항목을 골라요.
nth-child와 nth-of-type 비교
:nth-child()는 태그와 상관없이 모든 형제 요소를 센 다음에야 선택자의 나머지를 확인해요. :nth-of-type()은 같은 태그의 형제만 세요. 형제가 섞여 있으면 바로 차이가 드러나요.
양 끝에도 같은 짝이 있어요. :first-child / :first-of-type, :last-child / :last-of-type, :only-child / :only-of-type.
:not(), :is(), :where()
| 가상 클래스 | 예시 | 일치하는 것 |
|---|---|---|
:not(X) | li:not(.done) | X와 일치하지 않는 요소 |
:is(X, Y) | :is(h1, h2, h3) a | 목록 중 하나와 일치하는 요소 |
:where(X, Y) | :where(ul, ol) li | :is()와 같지만 명시도가 0 |
:has(X) | li:has(> input:checked) | X와 일치하는 것을 포함한 요소 |
매일 쓰는 건 :not()이에요. 예를 들어 항목 사이에 구분선을 넣되 마지막 항목 뒤에는 넣지 않을 때요.
상태 가상 클래스: focus, checked, disabled, invalid
| 가상 클래스 | 일치하는 것 |
|---|---|
:focus | 키보드나 마우스 포커스를 가진 요소 |
:focus-visible | 포커스를 가졌고, 브라우저가 링을 보여 줘야 한다고 판단할 때(보통 키보드 포커스) |
:focus-within | 포커스를 가진 요소를 포함한 요소 |
:checked | 체크된 체크박스, 라디오, 선택된 <option> |
:disabled / :enabled | 비활성화된(또는 활성화된) 폼 컨트롤 |
:required / :optional | required가 있는(또는 없는) 입력 요소 |
:invalid / :valid | 값이 검증을 통과하지 못한(또는 통과한) 입력 요소 |
:user-invalid | 유효하지 않지만, 사용자가 조작한 뒤에만 |
:placeholder-shown | 지금 placeholder를 보여 주는 입력 요소 |
:empty | 자식이 없는 요소, 텍스트도 없어야 해요 |
:target | id가 URL의 #fragment와 일치하는 요소 |
이메일 필드를 클릭해 보세요. :focus-within 덕분에 label이 파란색으로 바뀌어요. 이메일이 아닌 값을 입력하고 필드를 벗어나면 :user-invalid가 테두리를 주황색으로 바꿔요. 그냥 :invalid였다면 필수 입력인 빈 필드를 건드리기도 전에 주황색으로 표시했을 거예요.
:focus로 무엇을 하든 포커스가 눈에 보이게 유지하세요. 대체 스타일 없이 outline을 지우면 키보드 사용자는 자기가 어디 있는지 알 수 없어요.
:has(), 부모 선택자
:has()는 요소가 무엇을 포함하는지로 일치 여부를 판단해요. 오랫동안 요청되어 온 "부모 선택자"이고, 최신 Chrome, Firefox, Safari에서 동작해요.
다른 요금제를 골라 보세요. JavaScript 없이 카드 전체가 라디오 버튼을 따라가요.
자주 하는 실수
- 콜론 앞에 공백 넣기.
li :first-child는 "li 안의 첫 번째 자식"이라는 뜻이에요.li:first-child로 쓰세요. p:nth-child(1)을 "첫 번째 p"로 생각하기. "첫 번째 자식인데, 그게 p라면"이라는 뜻이에요. 첫 번째 p에는:first-of-type을 쓰세요.- 0부터 세기. 위치는 1부터 시작해요.
:nth-child(0)은 아무것도 고르지 않아요. - 포커스 outline 지우기. 대체 스타일 없는
:focus { outline: none }은 키보드 탐색을 망가뜨려요. :와::헷갈리기.:before는 가상 요소::before의 옛 표기이고, 가상 클래스는 항상 콜론 하나를 써요.
자주 묻는 질문
CSS에서 가상 클래스란 무엇인가요?
콜론 뒤에 오는 키워드로, 이름이 아니라 상태나 위치로 요소를 골라요. a:hover, li:first-child, input:focus 같은 것들이에요. 일반 선택자에 붙여 쓰고, 대부분의 가상 클래스는 명시도에서 클래스처럼 계산돼요(:where()는 0이에요).
CSS에서 nth-child는 어떻게 동작하나요?
:nth-child(an+b)는 n = 0, 1, 2 등에 대해 형제 사이의 위치가 a×n+b인 요소와 일치해요. 위치는 1부터 세요. :nth-child(3)은 세 번째 자식, :nth-child(odd)나 2n+1은 홀수 번째 전부, :nth-child(n+4)는 네 번째부터 끝까지예요.
nth-child와 nth-of-type은 무엇이 다른가요?
:nth-child()는 모든 형제 요소를 센 다음 선택자의 나머지를 확인하고, :nth-of-type()은 같은 종류의 형제만 세요. h2 뒤에 문단이 이어지는 목록에서 p:nth-child(1)은 아무것도 고르지 않지만 p:nth-of-type(1)은 첫 번째 문단을 골라요.
CSS에서 :not()은 어떻게 쓰나요?
제외할 선택자를 괄호 안에 넣어요. li:not(.done)은 done 클래스가 없는 모든 목록 항목과 일치해요. 목록도 받아요. input:not([type="checkbox"], [type="radio"])
가상 클래스와 가상 요소는 무엇이 다른가요?
가상 클래스(콜론 하나, :hover)는 어떤 상태에 있는 기존 요소 전체를 골라요. 가상 요소(콜론 두 개, ::before)는 요소의 일부를 대상으로 하거나 생성된 콘텐츠를 만들어요.