CSS의 :has() 가상 클래스 사용법
CSS에서 자식이나 후손 요소는 아주 쉽게 선택할 수 있지만, 부모나 조상 요소를 선택하는 것은 불가능한 일이 었습니다. 그래서 오랫동안 자바스크립트를 동원해서 이러한 문제를 해결하곤 했었죠.
하지만 CSS에 :has()
가상 클래스가 추가되면서 이것도 이제 옛말이 되었습니다.
웹 개발자들이 많이 기다렸던 만큼 2023년 State of JS 설문 조사 가장 많이 채택된 기능으로 뽑히고도 했었죠.
이번 포스팅에서는 비교적 최근에 CSS에 추가된 기능인 :has()
가상 클래스를 어떻게 사용하는지 알아보도록 하겠습니다.
본 포스팅은 CSS 선택자(selector)와 대한 기본적인 이해가 필요합니다. 관련해서는 제가 별도 포스팅에서 다루고 있으니 참고하세요.
기본 문법
CSS의 :has()
가상 클래스는 결합자(combinator)처럼 기본적으로 2개의 선택자를 필요로 합니다.
첫 번째 선택자로 선택된 HTML 요소의 안에 두 번째 선택자로 선택이 가능한 HTML 요소가 있다면 첫 번째 선택자로 선택된 요소에 선언한 스타일이 적용됩니다.
선택자1:has(선택자2) {
/* 스타일 선언 */
}
네, 맞습니다. 두 번째 선택자가 아닌 첫 번째 선택자에 스타일에 적용됩니다. 이 점이 CSS의 결합자와의 가장 큰 차이점이며, 기존에 CSS로 할 수 없었던 부모나 조상 요소를 선택하는 것이 가능해진 결정적인 이유입니다.
예를 들어, 내부에 <a>
요소가 있는 <p>
요소를 선택하여 스타일하고 싶다면 다음과 같이 CSS를 작성할 수 있고요.
p:has(a) {
/* 스타일 선언 */
}
비활성화 된 <input>
요소가 있는 <form>
요소를 선택하여 스타일하고 싶다면 싶다면 다음과 같이 CSS를 작성할 수 있습니다.
form:has(input:disabled) {
/* 스타일 선언 */
}
조상 요소를 선택할 때 가장 많이 사용되지만, 엄밀히 얘기하면 :has()
가상 클래스의 활용 범위는 더 넓습니다.
CSS 결합자에서 사용하는 >
, +
, ~
기호를 잘 활용하면, 부모 요소, 하나의 이전 형제, 여러 이전 형제도 선택할 수 있습니다.
이 부분에 대해서는 뒤에서 좀 더 설명드리도록 하겠습니다.
CSS 결합자에 대해서는 별도 포스팅에서 자세히 다루고 있으니 참고하세요.
조상 요소 선택
CSS에서 후손 요소를 선택하여 스타일하는 것은 아주 간단한 일입니다. 두 개의 선택자를 공백 문자로 연결해주면 첫 번째 선택자 안에서 두 번째 선택자와 부합하는 요소를 선택됩니다.
예를 들어, 다음과 같은 중첩된 상자가 있다고 가정해보겠습니다.
<div class="out">
<div class="in"></div>
</div>
out
클래스가 달린 요소 안에 있는 in
클래스가 달린 요소의 배경을 빨간색으로 칠하는 것은 쉽습니다.
.out .in {
background: red;
}
그런데 반대로 in
클래스가 달린 요소의 밖에 있는 out
클래스가 달린 요소를 선택하여 스타일하려면 어떻게 해야할까요? 🤔
예전에 이런 작업은 자바스크립트가 없이는 거의 불가능했었는데요.
이제는 CSS :has()
가상 클래스가 있으니 쉽게 해결할 수 있습니다.
CSS :has()
가상 클래스를 통해서 in
클래스가 달린 요소의 밖에 있는 out
클래스가 달린 요소의 배경을 초록색으로 칠해보겠습니다.
.out:has(.in) {
background: green;
}
만약에 in
클래스가 달린 요소의 직계 부모 요소를 상대로만 제한하고 싶다면 >
기호를 사용하면 됩니다.
.out:has(> .in) {
background: green;
}
이전 요소 선택
CSS 결합자를 사용해서 다음 요소를 어렵지 않게 선택하여 스타일할 수 있습니다.
두 개의 선택자를 +
기호로 연결해주면 첫 번째 선택자 다음으로 나오는 요소가 두 번째 선택자와 부합하면 선택이 되죠.
예를 들어, 다음과 같은 중첩된 상자가 있다고 가정해보겠습니다.
<div class="left"></div>
<div class="right"></div>
left
클래스가 달린 요소 다음에 오는 right
클래스가 달린 요소의 배경을 빨간색으로 칠해보겠습니다.
.left + .right {
background: red;
}
반대로 right
클래스가 달린 요소의 앞에 있는 left
클래스가 달린 요소를 선택하여 스타일하려면 어떻게 해야할까요? 🤔
마찬가지로 CSS :has()
가상 클래스를 이용하면 어렵지 않습니다.
right
클래스가 달린 요소의 앞에 있는 left
클래스가 달린 요소의 배경을 초록색으로 칠해보겠습니다.
.left:has(+ .right) {
background: green;
}
+
기호 대신에 ~
기호를 사용하면 바로 앞 뿐만 아니라 앞에 있는 모든 형제 요소를 선택할 수 있습니다.
.left:has(~ .right) {
background: green;
}
자식 상태에 따른 부모 스타일
:has()
가상 클래스의 기본적인 사용법을 배웠으니 이 번에는 좀 더 재미있는 예제를 보여드릴까요?
자식 요소의 상태에 따라서 부모 요소의 스타일을 변경해줘야 할 때 :has()
가상 클래스가 특히 유용하게 사용될 수 있는데요.
예를 들어, 3개의 색깔 버튼을 감싸고 있는 상자가 있다고 가정해보겠습니다.
<div>
<button class="red">빨강</button>
<button class="green">초록</button>
<button class="blue">파랑</button>
</div>
각 버튼을 누르고 있을 때 상자의 색깔이 이애 따라 바뀌게 하려면 어떻게 해야할까요?
부모 요소인 상자에 스타일을 적용해야 하니 :has()
가상 클래스를 사용해야할텐데요.
바로 :active
가상 클래스를 사용해서 자식 요소인 각 버튼이 활성화된 상태를 감지하면 되겠죠?
이 선택자를 :has()
가상 클래스의 인자로 넘겨주면 됩니다!
div:has(.red:active) {
background: red;
}
div:has(.green:active) {
background: green;
}
div:has(.blue:active) {
background: blue;
}
아래 웹 페이지에서 각 버튼을 누르고 계시면 상자의 배경색이 바뀌는 것을 보실 수 있으실 겁니다.
마치면서
지금까지 CSS에 추가된 :has()
가상 클래스 어떻게 사용하는지 실습을 통해서 함께 살펴보았습니다.
:has()
가상 클래스는 부모 요소나 이전 요소를 선택할 수 있게 해주는 아주 유용한 기능입니다.
대부분의 모던 브라우저에서 지원되는 기능이니 실무에서 잘 활용하실 수 있으셨으면 좋겠습니다.