웹사이트를 만들다 보면 늘 같은 벽에 부딪힙니다. "입력칸이 채워지면 라벨 색을 바꿔라", "카드 안에 이미지가 있으면 레이아웃을 다르게 해라" 같은 요구입니다. 화면에 보이는 결과는 단순한데, 그걸 구현하려면 자바스크립트로 요소를 일일이 감시하고, 상태가 바뀔 때마다 클래스를 붙였다 떼어야 했습니다. 코드는 길어지고, 버그가 숨을 자리도 늘어납니다.
그런데 CSS에 :has()라는 선택자가 들어오면서, 이 오래된 숙제의 상당 부분이 스타일시트 한 줄로 정리되기 시작했습니다.
자식을 보고 부모를 고르는, 단 하나의 선택자
지금까지 CSS는 위에서 아래로만 흘렀습니다. 부모를 먼저 고르고 그 안의 자식을 꾸미는 건 쉬웠지만, 반대로 "이런 자식을 가진 부모"를 고르는 일은 불가능에 가까웠습니다. 그래서 많은 개발자가 :has()를 오래 기다려 온 '부모 선택자'라고 부릅니다.
사용법은 직관적입니다. label:has(input:focus)라고 쓰면 "포커스된 입력칸을 품고 있는 라벨"을 골라 색을 줄 수 있고, .card:has(img)라고 쓰면 "이미지가 들어 있는 카드"만 따로 꾸밀 수 있습니다. 자바스크립트가 하던 '관찰하고 반응하기'를 브라우저가 알아서 처리합니다.
실무에서 :has()가 빛나는 순간
이 선택자는 작은 회사 웹사이트에서 특히 자주 만나는 장면들을 단번에 해결합니다.
- 문의 폼 검증 표시: 필수 입력칸이 비어 있으면 항목 전체를 붉게, 다 채우면 차분하게 — 자바스크립트 없이 입력 상태에 맞춰 바뀝니다.
- 이미지 유무에 따른 카드: 사진이 있는 후기와 글만 있는 후기를 같은 마크업으로 두고, 보이는 모습만 다르게 줄 수 있습니다.
- 메뉴가 열렸을 때 배경 처리: 드롭다운이 펼쳐진 동안에만 본문을 살짝 어둡게 하는 효과도 상태 클래스 없이 구현됩니다.
- 빈 영역 숨기기: 콘텐츠가 하나도 없는 섹션을 자동으로 접어, 빈 상자가 덩그러니 남는 일을 막습니다.
자바스크립트를 덜어내면 생기는 이점
단순히 코드가 짧아지는 것에 그치지 않습니다. 상태 변화를 브라우저가 직접 그리기 때문에 깜빡임이나 한 박자 늦는 반응이 사라집니다. 의존하던 라이브러리가 줄면 페이지가 가벼워지고, 그만큼 모바일에서 첫 화면이 빨리 뜹니다. 무엇보다 로직과 표현이 분리되어, 나중에 디자인을 손볼 때 자바스크립트를 건드릴 필요가 없어집니다.
도입 전 알아둘 점
:has()는 이미 크롬·사파리·엣지·파이어폭스 등 주요 최신 브라우저에서 모두 동작합니다. 다만 아주 오래된 브라우저를 쓰는 고객이 있다면, :has()가 적용되지 않아도 사이트가 망가지지 않도록 기본 상태를 단정하게 잡아두는 점진적 적용이 안전합니다. 핵심 기능을 :has() 하나에 의존시키기보다, '있으면 더 좋은 마감'으로 얹는 방식이 권장됩니다.
결국 중요한 건 '덜 깨지는' 사이트
새로운 CSS 기능이 반가운 이유는 화려해서가 아닙니다. 같은 결과를 더 적은 코드로, 더 적은 오류 가능성으로 만들 수 있기 때문입니다. 코드가 단순해질수록 사이트는 덜 깨지고, 오래 관리하기 쉬워집니다.
CYAN은 작은 회사의 웹사이트를 만들 때 이렇게 표준 기술이 대신해 줄 수 있는 일은 과감히 덜어내는 쪽을 택합니다. 화려한 장치를 잔뜩 붙이는 것보다, 몇 년 뒤에도 손이 덜 가는 사이트가 결국 사장님의 시간과 비용을 아껴 주기 때문입니다.