지금까지 CSS는 '위에서 아래로만' 흘렀다
웹 화면을 꾸미는 CSS에는 오랜 규칙이 하나 있었습니다. 부모가 자식을 고르는 건 되지만, 자식을 보고 부모를 고르는 건 안 된다는 것입니다. 그래서 '입력칸이 모두 채워졌을 때만 보내기 버튼을 켜기', '이미지가 든 카드만 여백을 넓히기' 같은 흔한 요구가 나오면, 개발자는 별수 없이 자바스크립트를 불러 화면을 실시간으로 감시하고 색과 상태를 손으로 갈아 끼워야 했습니다. 작은 기능 하나에 코드가 붙고, 그 코드가 언젠가 탈이 나 문의 폼이 조용히 멈추기도 했습니다.
:has()는 '안에 ~를 품은'을 읽는 선택자다
:has()는 오래 기다려 온 이른바 '부모 선택자'입니다. 이름 그대로 어떤 것을 품고 있는 요소를 골라냅니다. 예를 들어 form:has(input:invalid)는 '잘못 입력된 칸을 하나라도 품은 폼'을 뜻하고, .card:has(img)는 '이미지를 품은 카드'만 가리킵니다. 부모에서 시작해 안쪽을 들여다본 뒤, 조건이 맞으면 그 부모 자신에게 스타일을 입히는 것입니다.
이 한 줄로 사라지는 자바스크립트
- 폼 검증 표시: 빈칸이 남아 있으면 form:has(:invalid) 로 보내기 버튼을 흐리게, 다 채우면 또렷하게.
- 내용 유무에 따른 배치: 사진이 없는 후기 카드는 .review:has(.photo) 가 아닌 쪽으로 자동 처리.
- 메뉴 열림 상태: 하위 메뉴가 펼쳐진 항목만 li:has(.submenu:hover) 로 강조.
작은 회사 웹사이트에서 무엇이 달라지나
규모가 크지 않은 회사의 홈페이지일수록 이 변화가 반갑습니다. 화면 곳곳의 '조건부 반응'을 자바스크립트 없이 CSS 한 줄로 처리할 수 있으니, 코드가 가벼워지고 고장 날 곳이 줄어듭니다. 문의 폼의 버튼 상태, 후기 목록의 들쭉날쭉한 카드, 접히고 펼쳐지는 메뉴처럼 손님이 매일 마주하는 자잘한 반응이 안정적으로 돌아갑니다. 유지보수하는 입장에서도 '어느 스크립트가 이걸 켜고 끄더라'를 뒤질 일이 사라집니다.
이미 모든 주요 브라우저가 알아듣는다
한때 실험 기능으로만 여겨졌던 :has()는 이제 크롬·사파리·엣지·파이어폭스 최신 버전에서 모두 정식으로 동작합니다. 별도의 폴리필이나 플러그인 없이, 스타일시트에 그대로 적기만 하면 됩니다. 다만 아주 오래된 브라우저를 쓰는 손님을 위해서는 ':has()가 없어도 화면이 무너지지 않도록' 기본 모습을 먼저 잡아 두고 그 위에 얹는 방식이 안전합니다.
결국, 코드는 줄이고 안정은 늘리는 방향
웹 기술의 흐름은 늘 '손으로 감시하던 일을 언어가 대신 떠맡는' 쪽으로 흘러왔습니다. text-wrap 이 줄바꿈을, color-mix() 가 색 파생을 맡았듯, :has()는 '자식을 보고 부모를 바꾸는' 오래된 숙제를 CSS의 몫으로 되돌려 놓았습니다. CYAN은 이렇게 검증된 최신 표준을 작은 회사의 홈페이지에 알맞게 골라 얹어, 화면은 매끄럽되 뒤에서 고장 날 코드는 최대한 덜어 내는 방향으로 사이트를 짓습니다.