Contents
see List개요
CSS :has() 선택자는 "부모 선택자"라고 불리며, 특정 자식이나 후손 요소를 포함하는 부모 요소를 선택할 수 있게 해줍니다. 2024년부터 모든 주요 브라우저에서 완벽하게 지원되며, 기존에 JavaScript로만 가능하던 다양한 인터랙션 패턴을 순수 CSS만으로 구현할 수 있습니다.
이 선택자의 등장으로 CSS의 표현력이 획기적으로 확장되었으며, 조건부 스타일링, 폼 유효성 시각화, 동적 레이아웃 변경 등 실용적인 활용 사례가 매우 다양합니다.
핵심 개념
:has()는 관계형 의사 클래스(relational pseudo-class)로, 괄호 안의 선택자와 일치하는 요소를 포함하는 요소를 선택합니다.
- 기본 문법:
A:has(B)는 B를 후손으로 가진 A를 선택합니다. - 직계 자식:
A:has(> B)는 B를 직계 자식으로 가진 A를 선택합니다. - 인접 형제 조합:
A:has(+ B)는 바로 다음에 B가 오는 A를 선택합니다. - 부정 조합:
A:has(:not(B))는 B가 아닌 후손을 가진 A를 선택합니다. - 상태 기반:
A:has(input:checked)는 체크된 input을 포함하는 A를 선택합니다.
핵심은 :has()가 "상향 선택"을 가능하게 한다는 점입니다. CSS 역사상 처음으로 자식의 상태에 따라 부모를 스타일링할 수 있게 되었습니다.
실전 예제
JavaScript 없이 토글 카드를 구현하는 예제입니다. 체크박스의 상태에 따라 카드 전체의 스타일이 변합니다.
<div class="toggle-card">
<label class="toggle-card__header">
<input type="checkbox" class="toggle-card__input">
<span class="toggle-card__title">자세히 보기</span>
<span class="toggle-card__icon"></span>
</label>
<div class="toggle-card__content">
<p>숨겨진 콘텐츠가 여기에 표시됩니다.</p>
</div>
</div>
/* 체크박스 숨기기 */
.toggle-card__input {
position: absolute;
opacity: 0;
pointer-events: none;
}
/* 기본 상태 */
.toggle-card {
border: 2px solid #e2e8f0;
border-radius: 8px;
overflow: hidden;
transition: border-color 0.3s ease;
}
.toggle-card__content {
max-height: 0;
overflow: hidden;
transition: max-height 0.4s ease, padding 0.4s ease;
padding: 0 1.5rem;
}
.toggle-card__icon::after {
content: "+";
transition: transform 0.3s ease;
display: inline-block;
}
/* :has()로 체크 상태 감지 - 부모 카드 스타일 변경 */
.toggle-card:has(.toggle-card__input:checked) {
border-color: #3b82f6;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
}
.toggle-card:has(.toggle-card__input:checked) .toggle-card__content {
max-height: 500px;
padding: 1rem 1.5rem;
}
.toggle-card:has(.toggle-card__input:checked) .toggle-card__icon::after {
transform: rotate(45deg);
}
/* 폼 유효성 시각화 */
.form-group:has(input:invalid:not(:placeholder-shown)) {
--field-color: #ef4444;
}
.form-group:has(input:valid:not(:placeholder-shown)) {
--field-color: #22c55e;
}
활용 팁
- 폼 유효성 피드백:
form:has(:invalid)로 폼 내에 유효하지 않은 필드가 있을 때 제출 버튼 스타일을 변경할 수 있습니다. - 빈 상태 처리:
ul:has(li)와ul:not(:has(li))를 활용하면 목록이 비었을 때 다른 UI를 보여줄 수 있습니다. - 다크 모드 토글:
body:has(#dark-mode:checked)와 같이 전역 테마 전환도 CSS만으로 가능합니다. - 성능 고려: :has()는 브라우저가 최적화하고 있지만, 매우 복잡한 선택자 조합은 피하는 것이 좋습니다.
- 점진적 향상:
@supports selector(:has(*)) { }로 지원 여부를 확인하고 적용하세요.
마무리
CSS :has() 선택자는 웹 개발의 패러다임을 바꾸는 강력한 기능입니다. 간단한 토글부터 복잡한 조건부 레이아웃까지, JavaScript 의존도를 크게 줄이면서 성능과 접근성을 동시에 개선할 수 있습니다. CSS-only 인터랙션의 새 시대를 열어보시기 바랍니다.