상세 컨텐츠

본문 제목

CSS 선택자

HTML&CSS

by 이관모 2025. 9. 27. 22:03

본문

반응형

목표: CSS 선택자의 종류와 우선순위(특이성)를 이해하고, 폼·테이블·카드 레이아웃 등 실무에서 바로 쓰는 패턴을 예제로 익힙니다.


1) 기본 선택자

종류 예시 설명
전체 선택자 * { margin:0; } 모든 요소에 적용
태그(타입) p { ... } 특정 태그에 적용
클래스 .card { ... } 재사용 가능한 그룹
아이디 #main { ... } 문서 내 유일(고유) 요소
그룹화 h1, h2, h3 { ... } 여러 선택자에 동일 규칙

예제

<!-- HTML -->
<div class="card">
  <h3 id="title">Hello</h3>
  <p>본문입니다.</p>
</div>

<!-- CSS -->
* { box-sizing: border-box; }          /* 전체 */
.card { border:1px solid #e2e8f0; }    /* 클래스 */
#title { color:#2563eb; }              /* 아이디 */
p { margin:0; }                        /* 태그 */
h3, p { font-family: system-ui; }      /* 그룹 */

미리보기

Hello

본문입니다.


2) 결합자: 요소 간 관계 선택

결합자 예시 설명
공백(자손) .card p .card 내부의 모든 p(깊이 무관)
> (자식) .list > li .list의 직계 자식 li만
+ (인접 형제) h3 + p h3 바로 다음 p 하나
~ (일반 형제) h3 ~ p h3 뒤에 나오는 모든 p 형제

예제

<!-- HTML -->
<div class="card">
  <h3>제목</h3>
  <p>이 문단은 h3 바로 다음(+)</p>
  <div><p>이 문단은 자손(공백)</p></div>
  <p>이 문단은 형제들 중 하나(~)</p>
</div>

<!-- CSS -->
.card p { color:#0f766e; }      /* 자손 */
.card > p { font-weight:700; }  /* 자식 */
h3 + p { text-decoration:underline; }   /* 인접 형제 */
h3 ~ p { font-style:italic; }           /* 일반 형제 */

미리보기

제목

이 문단은 h3 바로 다음(+)

이 문단은 자손(공백)

이 문단은 형제들 중 하나(~)


3) 속성 선택자

형태 예시 의미
[attr] input[required] 속성이 존재
[attr="v"] a[target="_blank"] 정확히 일치
[attr^="v"] img[src^="https://"] v로 시작
[attr$="v"] img[src$=".png"] v로 끝남
[attr*="v"] a[href*="docs"] v 포함
[attr~="v"] [class~="active"] 공백 분리된 단어 중 v
[attr|="v"] [lang|="en"] v 또는 v-로 시작

예제

<!-- HTML -->
<input required placeholder="이름" />
<img src="https://example.com/photo.png" alt="샘플">
<a href="/docs/intro" target="_blank">문서</a>

<!-- CSS -->
input[required] { border:2px solid #f59e0b; }
img[src$=".png"] { outline:3px dashed #22c55e; }
a[href*="docs"][target="_blank"] { color:#2563eb; }

미리보기


4) 의사 클래스 (상태/위치)

  • :hover, :active, :focus: 상호작용 상태
  • :first-child, :last-child, :nth-child(n): 형제 내 위치
  • :checked, :disabled, :valid, :invalid: 폼 상태
  • :not(): 부정, :is()/:where(): 여러 선택자 그룹
  • :has(): “부모가 자식/후손을 가지면” 선택 (관계 선택)

예제

<!-- HTML -->
<button class="btn">버튼</button>
<ul class="menu">
  <li>하나</li> <li>둘</li> <li>셋</li>
</ul>
<input type="email" class="field" placeholder="이메일" required />

<!-- CSS -->
.btn:hover { transform: translateY(-2px); }
.menu li:nth-child(2) { color:#ef4444; }
.field:valid { outline:2px solid #22c55e; }
.field:invalid { outline:2px solid #ef4444; }
.menu li:not(:first-child) { font-style: italic; }

미리보기

  • 하나
  • 둘 (nth-child(2))
  • 셋 (not(:first-child))

※ 이메일 형식이면 초록, 아니면 빨강 아웃라인


5) 의사 요소 (::before, ::after, ::first-line, ::selection)

요소 내부의 특정 “가상 부분”을 선택합니다. ::before/::after를 쓰려면 content가 필요합니다.

예제

<!-- HTML -->
<p class="quote">배움은 끝이 없다.</p>

<!-- CSS -->
.quote::before { content:"“"; color:#2563eb; font-size:2rem; margin-right:.2rem; }
.quote::after { content:"”"; color:#2563eb; font-size:2rem; margin-left:.2rem; }
.quote::first-line { font-weight:700; }
::selection { background:#fde68a; color:#111; }

미리보기

배움은 끝이 없다.

텍스트를 드래그해보면 selection 색이 바뀌는 효과(브라우저별 다를 수 있음)


6) 특이성(우선순위) & :is / :where / :not / :has 정리

선택자 특이성 가중치(개념) 비고
ID 선택자(#id) 100 가급적 과사용 금지
클래스/속성/의사클래스(.cls, [a], :hover) 10 주력
태그/의사요소(p, ::before) 1 가벼움
전체선택자(*), 결합자(공백, >, +, ~) 0 특이성 없음
:is(…) 괄호 내부에서 가장 높은 값 가독성↑
:where(…) 항상 0 리셋/스코프에 유용
:not(…) 괄호 외부 선택자의 특이성만 내부는 추가X
:has(…) 괄호 내부에서 가장 높은 값 관계 선택

: 컴포넌트 스타일링은 .wrapper :where(h1, h2, p, a)처럼 :where를 쓰면 특이성 낮게 유지 → 나중에 오버라이드 쉬움.

예제

/* 스코프 낮추기 */
.card :where(h1, h2, p, a) { margin:0; }

/* 읽기 쉬운 다형 선택 */
.btn:is(.primary, .danger):hover { transform: translateY(-2px); }

/* 상태 부정 */
.input:not(:focus) { opacity:.9; }

/* 부모가 특정 자식/후손을 가질 때 */
.list:has(li.selected) { border-color:#22c55e; }

미리보기

  • 항목1
  • 항목2(selected)

※ 실제 :has 적용 결과는 브라우저에서 렌더링 시 반영됩니다.


7) 실무 패턴 5가지

패턴 A. 지그재그(줄무늬) 테이블

<table class="zebra">
  <thead><tr><th>#</th><th>이름</th><th>점수</th></tr></thead>
  <tbody>
    <tr><td>1</td><td>Kim</td><td>92</td></tr>
    <tr><td>2</td><td>Lee</td><td>81</td></tr>
    <tr><td>3</td><td>Park</td><td>88</td></tr>
  </tbody>
</table>

<style>
.zebra tbody tr:nth-child(even) { background:#f8fafc; }
.zebra tbody tr:hover { background:#eef2ff; }
</style>

미리보기

# 이름 점수
1 Kim 92
2 Lee 81
3 Park 88

패턴 B. 폼 상태 스타일 (required/valid/invalid)

<input class="ctl" type="email" placeholder="이메일" required>

<style>
.ctl:required { border:1px solid #94a3b8; }
.ctl:valid { outline:2px solid #22c55e; }
.ctl:invalid { outline:2px solid #ef4444; }
.ctl:focus { box-shadow:0 0 0 4px #dbeafe; }
</style>

미리보기

패턴 C. 카드 hover와 인접 형제

<div class="card2">
  <h4>타이틀</h4>
  <p>설명...</p>
</div>

<style>
.card2 { border:1px solid #e2e8f0; border-radius:12px; padding:12px; transition:.2s; }
.card2:hover { transform: translateY(-4px); box-shadow:0 10px 20px rgba(0,0,0,.06); }
.card2 h4 + p { color:#475569; } /* h4 바로 다음 문단 */
</style>

미리보기

타이틀

설명...

패턴 D. 탭 UI (라디오 :checked + 형제 결합자)

<div class="tabs">
  <input type="radio" id="t1" name="tabs" checked>
  <label for="t1">탭1</label>
  <input type="radio" id="t2" name="tabs">
  <label for="t2">탭2</label>

  <div class="panel p1">패널 1</div>
  <div class="panel p2">패널 2</div>
</div>

<style>
.tabs input { display:none; }
.tabs label { padding:.4rem .8rem; border:1px solid #cbd5e1; border-bottom:none; cursor:pointer; }
.tabs .panel { display:none; border:1px solid #cbd5e1; padding:10px; }
#t1:checked ~ .p1, #t2:checked ~ .p2 { display:block; }
#t1:checked + label, #t2:checked + label { background:#eef2ff; }
</style>

미리보기

탭1 탭2
패널 1

패턴 E. 부모 조건 스타일(:has)

<ul class="list">
  <li>A</li>
  <li class="selected">B</li>
</ul>

<style>
.list:has(.selected) { border:2px solid #22c55e; }
.list li.selected { font-weight:700; color:#16a34a; }
</style>

미리보기

  • A
  • B (selected)

8) 연습문제

  1. 결합자: 카드(.card) 안에서 h3 다음에 오는 p만 밑줄 긋기 (+ 사용)
  2. 속성 선택자: a[target="_blank"]에 아이콘 붙이기(::aftercontent)
  3. 의사 클래스: 리스트 2,4,6번째 항목만 배경 색칠 (:nth-child(2n))
  4. 부정: .btn.danger아닌 버튼만 파란 테두리 (:not(.danger))
  5. :where: 래퍼 .article 내부의 h1, h2, p 공통 여백을 특이성 0으로 초기화

정답은 위 섹션 예제들을 조합해 스스로 만들어보세요. 특이성이 꼬이면 :where()로 낮추고, 모듈별 래퍼 클래스를 꼭 쓰는 습관을 들이면 좋아요.


반응형

'HTML&CSS' 카테고리의 다른 글

CSS Flexbox 완전 정복  (0) 2025.10.02
CSS 글꼴 설정  (0) 2025.09.30
HTML에서 자주 쓰는 태그 20종류  (0) 2025.09.25
HTML 폼태그와 입력요소들  (3) 2025.09.24
HTML 표 만들기 (table태그)  (0) 2025.09.24

관련글 더보기