:has() 셀렉터

dev | 2023-07-16

부모 요소 셀렉터는 오래전 부터 많은 개발자들이 원하는 기능이었다. 하지만 탐색 순서나 순환 참조와 같은 브라우저 성능과 관련된 구현 문제가 있어서 오랬동안 실현되지 못했다. 20여년이 지나서야 CSS4 스펙에 추가되고 2021년에 구현을 시작한 브라우저가 나오고 2022년에 기능을 탑재한 브라우저들이 출시됐다. 지금은 파어어 폭스를 제외한 대부분의 브라우저가 :has()를 지원하고 있다. 파이어 폭스도 설정으로 활성화 할 수 있고 곧 나올 것으로 기대된다. 나는 신기술을 좀 보수적으로 적용하는 편인데 :has() 셀렉터는 적용했을 때 얻을 수 있는 이득이 상당해서 최근에 업무에 적용해 보았다.

첫번째는 링크의 밑줄을 선택적으로 적용하는 경우다. 링크에는 밑줄을 넣어서 링크인지 알아보기 쉽게 하는데 경우에 따라서 링크 안의 요소가 복잡한 경우 밑줄을 다 넣기가 힘들다. 이럴 때 컨텐츠에 따라서 밑줄을 선택적으로 표현해 줄 수 있다. :not()과 조합해서 특정 요소가 없을 때에만 밑줄을 넣도록 했다.

a:hover:not(:has(.avatar)) {
  ...
  text-decoration: underline;
}

또한 부모 요소를 선택하는 경우 뿐만 아니라 형제 요소를 선택할 때도 사용할 수 있다. h1h2가 연달아 있을 때 h2h1 + h2로 쉽게 선택할 수 있다. 하지만 h1을 선택할 수 있는 방법은 딱히 없어서 추가 클래스 지정이 필요했었는데 이제는 h1:has(+ h2)와 같이 사용하면 선택이 가능하다.

비슷한 상황을 실제로 적용해 봤는데 목록 테이블에 페이지네이션이 있는지 여부에 따라 테이블에 둥근 모서리를 선택적으로 적용하는 경우였다. 페이지네이션이 있을 때는 목록 테이블 하단에 둥근 모서리가 없어야 하고 반대의 경우는 둥근 모서리가 적용되어야 하는 경우다.

.table-list {
  ...
  border-radius: 8px;
}
.table-list:has(+ .pagination) {
  ...
  border-radius: 8px 8px 0 0;
}

목록 테이블만 있는 경우

.table-list

목록과 페이지네이션이 같이 있는 경우

.table-list
.pagination

:has() 셀렉터를 지원하지 않는 브라우저에서는 페이지네이션이 같이 있는 경우의 .table-list 아래 둥근 모서리가 남아 있다.

:has() 셀렉터는 CSS의 선언적인 특성을 아주 잘 나타내주는 기능이다. 조건별로 디자인이 달라져야 하는 경우 많은 사람들이 자바스크립트의 조건문을 먼저 또올리는데 CSS가 이런 경우를 잘 제어할 수 있게 고안되어 있기 때문에 CSS를 활용하면 더 쉽게 해결되는 경우가 많다. :has() 셀렉터를 사용하면 다양한 컴포넌트 조합의 상황에서도 표현과 관련된 로직을 CSS로 제어할 수 있기 떄문에 코드 구조 측면이나 생산성, 유지 운영 등 다양한 측면에서 이점이 있을 것으로 생각된다.

Comments

    Post a comment

    :

    : 공개 되지 않습니다. Gravatar를 표시 합니다.

    :

    : HTML 태그를 사용할 수 없습니다.