🎯 CSS 선택자 완전 정리 – 기본, 결합, 속성, 가상 클래스/요소
CSS에서 선택자(selector)는 스타일을 적용할 HTML 요소를 지정하는 가장 기본적인 개념입니다. 하지만 실제로는 다양한 형태의 선택자가 있으며, 이를 정확히 이해하면 유지보수와 확장성이 훨씬 쉬워집니다.
1️⃣ 기본 선택자
*
(전체 선택자): 문서의 모든 요소를 선택* { margin: 0; }
태그명
선택자: 특정 태그를 선택p { font-size: 16px; }
.클래스
선택자: 특정 클래스가 지정된 요소.title { color: red; }
#아이디
선택자: 특정 id가 지정된 요소#main { background: #eee; }
✔️ 주의: id
는 페이지 내에서 유일해야 하며, 너무 자주 사용하는 것은 지양하는 것이 좋습니다.
2️⃣ 결합 선택자
<div class="button">
<span class="primary">텍스트</span>
<div>
<span class="primary">텍스트2</span>
</div>
</div>
<div class="sibling">
</div>
<div class="sibling2">
</div>
<div class="sibling3">
</div>
- 후손 선택자:
A B
→ A 내부의 B (후손 모두)div p { ... }
- 자식 선택자:
A > B
→ A의 자식인 B (직속 자식만)ul > li { ... }
- 인접 형제 선택자:
A + B
→ A 바로 뒤의 Bh1 + p { ... }
- 일반 형제 선택자:
A ~ B
→ A 뒤에 오는 모든 B 형제h1 ~ p { ... }
실전 팁: 자식 선택자는 구조가 명확할 때 사용하고, 후손 선택자는 성능에 영향을 줄 수 있으니 최소화하는 것이 좋습니다.
3️⃣ 속성 선택자
[type]
→ 속성이 존재하는 요소input[type]
[type="text"]
→ 정확히 일치하는 값input[type="text"]
[href^="https"]
→ 특정 값으로 시작a[href^="https"]
[href$=".pdf"]
→ 특정 값으로 끝남a[href$=".pdf"]
[data-role*="admin"]
→ 특정 문자열을 포함div[data-role*="admin"]
활용 팁: data-*
속성과 조합하면 JavaScript 없이도 유연한 스타일링 가능!
✅ CSS 예시
[data-status="active"] {
background-color: green;
}
[data-role*="admin"] {
font-weight: bold;
}
[attr="val"] {...} /* 정확히 일치 */
[attr^="val"] {...} /* val로 시작 */
[attr$="val"] {...} /* val로 끝남 */
[attr*="val"] {...} /* val을 포함 */
✅ HTML 예시
<div data-role="admin">👑 관리자</div>
<div data-role="admin-user">👤 관리자-사용자</div>
<div data-role="user-admin-view">👁 사용자-관리자 보기</div>
<div data-role="user">🙋 일반 사용자</div>
<button id="highlightBtn" class="btn">관리자 관련 요소 강조</button>
<button id="undoHighlightBtn" class="btn">초기화</button>
<script>
document.getElementById("highlightBtn").addEventListener("click", () => {
// 'admin'이라는 단어가 포함된 data-role을 가진 요소들을 모두 선택
const adminElements = document.querySelectorAll('[data-role*="admin"]');
// 각 요소에 스타일을 적용
adminElements.forEach(el => {
el.style.backgroundColor = "gold";
el.style.border = "2px solid orange";
el.style.padding = "0 5px";
});
});
document.getElementById("undoHighlightBtn").addEventListener("click", () => {
// 'admin'이라는 단어가 포함된 data-role을 가진 요소들을 모두 선택
const adminElements = document.querySelectorAll('[data-role*="admin"]');
// 각 요소에 스타일을 적용
adminElements.forEach(el => {
el.style.backgroundColor = "";
el.style.border = "";
el.style.padding = "";
});
});
</script>
<style>
.btn {
border: 1px solid black;
display:border-box;
background: gray;
}
</style>
실전 팁: data-* 속성에는 단일값 말고 공백으로 구분 된 list처럼 다중값을 넣을 수도 있지만, 실제 현업에서는 data-* 속성에 단일 값을 넣는 경우가 훨씬 많습니다_ 상태, ID, 타입, 모드 등 조건을 분기하거나, 스타일링, 액션 제어가 대부분입니다. (9할)
다중 값을 쓰는 경우는 주로 특수한 상황이나 의도적으로 구조회된 데이터를 넣을 때만 사용합니다_ 사용자 역할, 태그처럼 한 요소가 여러 개의 속성을 가질 때 선택적으로 사용합니다. (1할)
참고: data-* 속성 A to Z 보러가기 👉 https://blog.naver.com/devops_log/223867090210
4️⃣ 가상 클래스 선택자 (pseudo-classes)
:hover
→ 마우스 올렸을 때:focus
→ 포커스 됐을 때:nth-child(n)
→ n번째 자식 요소li:nth-child(2n)
(짝수):first-child
,:last-child
→ 첫/마지막 자식:not(selector)
→ 제외할 때div:not(.active)
실전 팁: :hover
나 :focus
는 버튼, 링크 등 인터랙션 요소에 꼭 사용하세요.
✅ CSS 예시
/* 1. 버튼에 마우스를 올리면 색이 바뀜 */
button:hover {
background-color: #007bff;
color: white;
}
/* 2. 누르는 순간 눌리는 느낌 구현 */
button:active {
transform: scale(0.98);
}
/* 3. 클릭 또는 탭키로 포커스된 input 강조 */
input:focus {
outline: 2px solid #4CAF50;
}
/* 4. 체크된 항목에 따라 라벨 스타일 변경 */
input[type="checkbox"]:checked + label {
font-weight: bold;
color: green;
}
/* 5. 비활성화된 버튼에 스타일 지정 */
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* 6. 리스트 항목 중 첫 번째, 마지막, 특정 순서 항목 지정 */
ul li:first-child {
font-weight: bold;
}
ul li:nth-child(2) {
color: red;
}
ul li:last-child {
border-bottom: none;
}
/* 7. 제외조건 .primary가 아닌 버튼만 회색 처리 */
button:not(.primary) {
background-color: #eee;
}
/* 8. :nth-of-type(n) – 특정 태그 순서 */
p:nth-of-type(2) {
color: blue;
}
/* 9. :empty – 자식이 없는 요소 숨김 처리 */
div:empty {
display: none;
}
/* 10. :root – CSS 변수 선언 시, 전역 변수의 시작 지점 (HTML의 최상단) */
:root {
--main-color: #3f51b5;
}
button {
background-color: var(--main-color);
}
✅ 보너스: Form 관련 자주 쓰는 가상 클래스
선택자ㅌ | 선택자설명 |
:focus | 포커스된 input 요소 |
:valid / :invalid | 유효성 검사 통과 여부 |
:required / :optional | 필수 입력 여부 |
:checked | 체크박스 / 라디오 버튼 체크 여부 |
input:invalid {
border-color: red;
}
5️⃣ 가상 요소 선택자 (pseudo-elements)
::before
,::after
→ 요소 앞/뒤에 콘텐츠 삽입p::before { content: "👉"; }
::first-letter
→ 첫 글자p::first-letter { font-size: 2em; }
::selection
→ 텍스트 선택 영역 스타일링::selection { background: yellow; }
✅ 사용예시
<p class="test">공지사항 <hr/> 공지사항 내용입니다. </p>
<input class="test" type="text" placeholder="이름을 입력하세요" />
<ul>
<li class="test">항목 1</li>
<li class="test">항목 2</li>
</ul>
<!-- 렌더링 시: 📌 공지사항 ... -->
<style>
/* 1. 앞뒤 콘텐츠 삽입 */
p.test::before {
content: "📌 ";
}
p.test::after {
content: " 끝!";
color: red;
}
/* 2. 첫 글자에 스타일 (잡지) */
p.test::first-letter {
font-size: 2em;
color: darkblue;
font-weight: bold;
}
/* 3. 첫 줄에만 스타일 */
p.test::first-line {
color: green;
font-variant: small-caps;
}
/* 4. ::placeholder 텍스트 스타일 */
input.test::placeholder {
color: #888;
font-style: italic;
}
/* 5. 텍스트 드래그했을 때 스타일 */
p.test::selection {
background: yellow;
color: black;
}
/* 6. ul, ol의 불릿(•) 또는 번호에 스타일 */
li.test::marker {
color: red;
font-size: 1.5em;
}
</style>
공지사항
공지사항 내용입니다.
- 항목 1
- 항목 2
주의: ::before나 ::after 사용 시 content 속성은 필수입니다. 없으면 아무것도 안 보임.
✅ 실무에서 가장 많이 쓰는 조합
✅ 버튼 또는 태그 꾸미기
.button::after {
content: '→';
margin-left: 8px;
color: #333;
}
<button class="button">더보기</button>
✅ 리스트 항목 강조 (커스텀 불릿)
li::before {
content: "✔ ";
color: green;
}
✅ 팝업/모달 뒤에 배경 흐림 처리
.modal::before {
content: "";
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.5);
z-index: -1;
}
🔍 마무리 – 선택자 우선순위 요약
선택자 | 우선순위 점수 | 설명 |
---|---|---|
인라인 스타일 | 1000 | 요소에 style="color:red"처럼 직접 지정한 경우 |
#id | 100 | #header, #main처럼 id로 지정한 경우 |
.class, :pseudo-class, [attribute] | 10 | 클래스, 의사 클래스(:hover), 속성 선택자 |
태그, ::pseudo-element | 1 | HTML 태그 이름 자체를 선택하거나 의사 요소 사용 |
* (전체), 결합자 | 0 | 전체 선택자나 단순 구조 결합자는 점수 없음 |
예시 비교
<div id="myDiv" class="box" style="color: red;">텍스트</div>
<style>
div { color: blue; } /* 점수: 1 */
.box { color: green; } /* 점수: 10 */
#myDiv { color: orange; } /* 점수: 100 */
</style>
- 숫자가 높을수록 우선 적용됨
- !important는 점수와 상관없이 우선순위를 무시하고 최상위로 적용됨
- 점수가 같다면 나중에 선언된 것이 우선
- 선택자의 종류를 알면 상황에 맞는 정확한 스타일링이 가능해집니다. 가독성과 유지보수를 위해 너무 복잡한 선택자 조합은 피하는 것이 좋습니다.
✅ 예제 1: 지나치게 구체적인 조합
html body div.container ul > li.active span.label {
color: red;
}
점수 계산:
- 태그 선택자: html, body, div, ul, li, span → 6 × 1 = 6점
- 클래스: .container, .active, .label → 3 × 10 = 30점
- 결합자(>, 공백)는 점수 없음
총점: 36점
➡️ 너무 많은 구조에 의존해 스타일을 지정하고 있음
➡️ HTML 구조가 바뀌면 깨지기 쉬움
✅ 예제 2: ID와 클래스, 속성 혼합
#header .menu li.item[type="button"]:hover::after {
content: "!";
}
점수 계산:
- #header → 100점
- .menu, .item, :hover → 3 × 10 = 30점
- [type="button"] → 10점
- li → 1점
- ::after → 1점
총점: 142점
➡️ 점수가 너무 높아서 다른 스타일로 덮기가 매우 어려움
➡️ 이런 스타일은 나중에 오버라이드하려면 **!important**까지 써야 하는 경우도 생김
🧨 이런 복잡한 선택자의 단점
- 재사용이 어려움
HTML 구조가 바뀌면 선택자가 무용지물됨 - 유지보수가 어려움
다른 사람이 스타일 구조를 파악하기 어려움 - 우선순위 전쟁 발생
나중에 덮어쓰려면 더 강한 선택자나 !important 사용이 필요해짐
✅ 추천 방식
- .button.primary 처럼 클래스 조합 중심 (<div class="button primary">버튼</div> 두 클래스 모두 가진 요소)
- ID는 최소 사용
- 너무 깊은 구조 의존(X) → .menu-item.active처럼 간결하게
📌 다음 글 예고
다음 글: “CSS 박스 모델(Box Model) 완전 이해 – margin, border, padding, content” 에서는 실제 브라우저가 요소의 크기를 계산하는 방식을 시각적으로 설명합니다.
'language > css' 카테고리의 다른 글
🎯 CSS 단위 총정리 – px, em, rem, %, vw/vh, fr (0) | 2025.05.12 |
---|---|
🎯 display 속성 제대로 이해하기 (inline, block, flex, grid, none) (1) | 2025.05.11 |
🎯 CSS position 속성 차이 총정리 (static, relative, absolute, fixed, sticky) (1) | 2025.05.11 |
🎯 CSS 박스 모델(Box Model) 완전 이해 – margin, border, padding, content (0) | 2025.05.11 |
CSS란? – 웹에 스타일을 입히는 기술의 시작 | HTML에 색을 입히고 형태를 잡아주는 기술 (0) | 2025.04.11 |
댓글