가상 클래스 중 하나인 함수형 가상 클래스(Functional pseudo-class)에 대해 알아보겠습니다. 함수형 가상 클래스는 선택자 목록을 인수로 받는 가상 클래스를 말합니다.
함수형 가상 클래스의 장점 중 하나는 유효하지 않은 선택자 목록도 인수로 받을 수 있다는 점입니다.
/* 콤마(,)로 구분된 선택자 목록 */
ul, ol, button:unsupported {
/* 이 경우 선택자 목록 전체가 동작하지 않음 */
}
/* :is() 가상 클래스 함수 */
:is(ul, ol, button:unsupported) {
/* 유효하지 않은 button 태그를 제외하고 ul, ol 태그만을 인수로 받음 */
}
:is()와 :where()는 선택자 목록을 인수로 받아 그 중 선택 가능한 모든 요소들을 선택하는 가상 클래스입니다.
<div>This is red</div>
<ul>
<li>
This is also red.
</li>
</ul>
<p class="content">
This is also red.
</p>
<span>I'm red too!</span>
:is(div, ul, p.content, span) {
color: red;
}
:is()는 복잡한 선택자 목록을 다룰 때 특히 유용합니다.
/* 복잡한 중첩 선택자 목록 */
main section h3,
main section h4,
main section div.title,
main article h3,
main article h4,
main article div.title,
div section h3,
div section h4,
div section div.title,
div article h3,
div article h4,
div article div.title {
font-weight: 800;
}
위의 예제를 :is()를 사용할 경우 다음과 같이 나타낼 수 있습니다.
:is(main, div) :is(section, article) :is(h3, h4, div.title) {
font-weight: 800;
}
:is()와 :where()는 기본적으로 같은 기능을 하지만 차이점은 선택자 우선순위입니다. :is()가 인수로 받은 선택자 중 가장 순위가 높은 선택자와 같은 우선순위를 가진다면, :where()는 항상 0의 우선순위를 가집니다.
그렇기 때문에 :where()로 선택한 요소에 새로 적용하는 스타일보다 원래 있던 스타일이 우선시 됩니다.
<section class="is-styling">
<h3 class="is-styling">
<a>This is red.</a>
</h3>
<ul class="is-styling">
<li>This is also red.</li>
<li>This is also red.</li>
</ul>
</section>
<section class="where-styling">
<h3 class="where-styling">
<a>:where() makes this blue, but it's still green.</a>
</h3>
<ul class="where-styling">
<li>This is also green.</li>
<li>This is also green.</li>
</u>
</section>
section ul li {
color: green;
}
:is(section.is-styling) :is(h3.is-styling, ul.is-styling) :is(a, li) {
color: red;
}
:where(section.where-styling) :where(h3.where-styling, ul.where-styling) :where(a, li) {
color: blue;
}
:not()은 인수로 받은 선택자 목록을 포함하지 않는 나머지 요소를 선택하는 가상 클래스입니다.
<div class="circle small"></div>
<div class="circle outlined"></div>
<div class="circle large"></div>
.circle {
width: 20px;
height: 20px;
border: 1px solid black;
border-radius: 50%;
box-sizing: border-box;
}
/* small 클래스가 아닌 circle 클래스의 div 요소에 더 두꺼운 테두리 적용*/
div.circle:not(.small) {
border: 3px solid black;
}
.circle.large {
width: 30px;
height: 30px;
}
:not()은 :is()와 같은 선택자 우선순위 방식을 가집니다.
:has()는 2023년부터 지원하기 시작한 비교적 최근의 사양입니다. https://caniuse.com/css-has
:has()는 복합 선택자와 비슷하게 동작합니다. 가상 클래스의 원본 요소로부터 조건에 맞는 요소를 선택할 수 있습니다.
<article>
<h1>Title</h1>
<h2>Subtitle</h2>
<h2>Author</h2>
<p>Paragraph</p>
</article>
/* h1 바로 다음에 오는 h2만 선택하고 싶을 때 */
h1:has(+ h2) {
font-weight: 600;
}
:has() 또한 :is()와 같은 방식의 선택자 우선순위를 가집니다.