:has()
함수형 가상 클래스
:has()
함수형 가상 클래스 선택자는
괄호()
안의 형제, 자손 관계 선택자 목록 중 하나라도 관계를 가지고 있으면 요소를 선택합니다.
하나 이상의 여러 형제, 자손 관계 선택자를 쉼표로 구분하여 묶어, 그 중 하나라도 일치하는 관계가 있는 경우의 요소를 나타냅니다.
괄호()
안의 형제, 자손 관계 선택자 목록에 여러 개의 선택자를 사용할 때 사용하는 쉼표(,
)는 "또는(or)"이라고 해석합니다. 예를 들어, :has(A, B, C)
는 "A 또는 B 또는 C와의 관계를 가지고 있으면 선택"과 같은 논리적 의미를 가집니다.
구문
/* <한 개의 형제, 자손 관계 선택자 목록> */
:has(+ p) {} /* 바로 뒤의 p 요소와 형제 관계를 가지는 모든 요소를 선택 */
h1:has(> span) {} /* span 요소와 부모 관계를 가지는 h1 요소를 선택 */
.a:has(span) {} /* span 요소와 조상 관계를 가지는 a 클래스 값을 가지는 요소를 선택 */
/* <여래 개의 형제, 자손 관계 선택자 목록>
쉼표(,)로 구분합니다.
쉼표(,) 앞 뒤의 띄어쓰기는 없거나 있거나 동일하게 작동합니다.
*/
:has(+ p, > span) {} /* 바로 뒤의 p 요소와 형제 관계를 가지거나,
span 요소와 부모 관계를 가지는 모든 요소를 선택 */
h1:has(+ p, span) {} /* 바로 뒤의 p 요소와 형제 관계를 가지거나,
span 요소와 조상 관계를 가지는 h1 요소를 선택 */
.a:has(~ span, + p) {} /* 이후에 위치한 span 요소와 형제 관계를 가지거나,
바로 뒤의 p 요소와 형제 관계를 가지는 a 클래스 값을 가지는 요소를 선택 */
:has()
함수형 가상 클래스 선택자를 제대로 이해하려면,
괄호()
안에 지정하는 형제, 자손 관계 선택자 목록의 형제, 자손 관계 선택자의 개념을 알아야 합니다.
형제, 자손 관계 선택자
형제, 자손 관계 선택자는 간단히 관계 선택자(Relative selectors)라고도 불리며, 자손 또는 형제 간 관계를 정의하여 요소를 선택할 수 있게 합니다. 이는 :has()
와 함께 사용되지만, 기본적인 CSS 선택자로도 자주 사용됩니다.
이러한 관계 선택자를 요약하면 다음과 같습니다.
- 자손 선택자:
선택자A 선택자B
- 자식 선택자:
선택자A > 선택자B
- 이후(Subsequent) 형제 선택자:
선택자A ~ 선택자B
- 다음(Next) 형제 선택자:
선택자A + 선택자B
자손 선택자: 선택자A 선택자B
선택자A 선택자B
형태의 선택자로,
두 개의 복합 선택자를 구분하는 띄어쓰기(" "
, 공백)가 있으며 선택자A
요소 안에 위치한 타깃 자손 요소인 선택자B
를 모두 선택합니다.
(자손이란 자식, 자식의 자식, 자식의 자식의 자식... 등 모든 자손을 의미합니다.)
/* 예시: div 요소의 자손 p 요소를 선택 */
div p {
color: red;
}
더 자세한 설명은 CSS 자손 선택자 – 요소의 타깃 자손 요소를 모두 선택을 참조하세요.
자식 선택자: 선택자A > 선택자B
선택자A > 선택자B
형태의 선택자로,
두 개의 복합 선택자를 구분하는 기호(>
)가 있으며 선택자A
요소 안에 위치한 타깃 자식 요소인 선택자B
를 모두 선택합니다. 기호(>
) 앞 뒤의 띄어쓰기는 없거나 있거나 동일하게 작동합니다.
(자식이란 직계 자식만을 의미합니다. 자식의 자식, 자식의 자식의 자식.. 등의 자손을 의미하지 않습니다.)
/* 예시: div 요소의 직계 자식 p 요소를 선택 */
div > p {
color: blue;
}
더 자세한 설명은 CSS 자식 선택자 (>) - 요소의 타깃 자식 요소를 모두 선택을 참조하세요.
이후(Subsequent) 형제 선택자: 선택자A ~ 선택자B
선택자A ~ 선택자B
형태의 선택자로,
두 개의 복합 선택자를 구분하는 물결 기호(~
, tilde라고도 함)가 있으며 선택자A
이후(반드시 바로 뒤에 올 필요는 없음)에 위치한 모든 타깃 형제 요소인 선택자B
를 선택합니다. 기호(~
) 앞 뒤의 띄어쓰기는 없거나 있거나 동일하게 작동합니다.
(이 두 선택자는 모두 같은 부모 요소의 자식 요소입니다.)
/* 예시: div 요소 이후에 위치한 형제인 모든 p 요소를 선택 */
div ~ p {
color: blue;
}
더 자세한 설명은 CSS 이후 형제 선택자 (~) – 요소 뒤에 있는 모든 타깃 형제 요소를 선택을 참조하세요.
다음(Next) 형제 선택자: 선택자A + 선택자B
선택자A + 선택자B
형태의 선택자로,
두 개의 복합 선택자를 구분하는 플러스 기호(+
)가 있으며 선택자A
바로 다음에 위치한 타깃 형제 요소인 선택자B
를 선택합니다. 기호(+
) 앞 뒤의 띄어쓰기는 없거나 있거나 동일하게 작동합니다.
(이 두 선택자는 모두 같은 부모 요소의 자식 요소입니다.)
/* 예시: div 요소 바로 뒤에 위치한 형제인 p 요소를 선택 */
div + p {
color: blue;
}
더 자세한 설명은 CSS 다음 형제 선택자 (+) – 요소 바로 뒤에 있는 타깃 형제 요소를 선택을 참조하세요.
예제
여러 예제를 통해서 :has()
함수형 가상 클래스 선택자의 사용법에 대해 알아보겠습니다.
정말 간단한 예제
다음은 :has()
함수형 가상 클래스 선택자의 사용법의 이해를 위한 정말 간단한 예제입니다.
<h4>h4 제목 요소 입니다.</h4>
<p>p 요소입니다.</p>
<h5>h6 제목 요소 입니다.</h5>
<p>요소입니다.</p>
/* 바로 뒤의 p 요소와 형제 관계를 가지는 h4 요소를 선택 */
h4:has(+ p) {
background-color: yellowgreen;
}
h4 제목 요소 입니다.
p 요소입니다.
h6 제목 요소 입니다.
요소입니다.
약간 복잡해 보일 수 있지만 유용한 예제 💖
다음의 예제는 :has()
함수형 가상 클래스 선택자의 실제로 매우 유용한 적용 사례를 보여줍니다.
주어진 코드에서는 :has()
를 사용하여 특정 상태(체크된 라디오 버튼)에 따라 스타일을 동적으로 적용하는 방법을 보여주고 있습니다.
:focus-within
등을 제외한 대부분의 CSS 선택자는 자손 요소를 타깃으로 선택하거나, 나중에 마크업한 형제 요소를 타깃으로 선택할 수는 있지만, 조상 요소를 선택하거나 이전에 마크업한 형제 요소를 타깃으로 선택할 수 없습니다.
하지만, :has()
를 활용하면 형제, 자손 관계를 기반으로 조상 요소나 이전에 마크업한 형제 요소까지 타깃으로 선택할 수 있어서 CSS 선택자의 범용성이 크게 확장됩니다.
<fieldset>
<legend>관심이 있는 웹 언어를 선택하세요.</legend>
<div class="control-unit">
<input type="radio" id="html" name="web-lang">
<label for="html">HTML</label>
</div>
<div class="control-unit">
<input type="radio" id="css" name="web-lang" checked>
<label for="css">CSS</label>
</div>
<div class="control-unit">
<input type="radio" id="js" name="web-lang">
<label for="js">JavaScript</label>
</div>
</fieldset>
fieldset {
border: none;
}
.control-unit {
padding: 0.5em;
border: 1px solid silver;
border-radius: 6px;
}
/* 바로 뒤의 .control-unit 요소와 형제 관계를 가지는 .control-unit 요소를 선택 */
/* .control-unit를 기준으로 이전에 마크업한 형제 요소를 타깃으로 선택 */
.control-unit:has(+ .control-unit) {
margin-bottom: 0.5em;
}
/* :checked 상태인 요소와 조상 관계를 가지는 .control-unit 요소를 선택 */
/* :checked를 기준으로 조상 요소를 타깃으로 선택 */
.control-unit:has(:checked) { /* :checked 앞에 띄어쓰기는 없거나(:checked) 있거나( :checked) 동일하게 작동합니다. */
border-color: red;
accent-color: red;
}
코드 부연설명
:checked
가상 클래스 선택자는
라디오 버튼(<input type="radio">
)과 체크박스(<input type="checkbox">
)가 체크된 상태일 때 해당 요소를 선택합니다.
코드 부연설명
accent-color
속성은
브라우저가 기본 스타일을 제공하는 체크박스, 라디오 버튼, 슬라이더, 프로그레스 바 등의
사용자 인터페이스 요소에 적용되어 있는 강조 색상을 변경하는 데 사용됩니다.
CSS 선택자의 구체성 값(명시도)
:has()
자체는 CSS 선택자의 구체성 값(명시도)의 규칙에서 아무런 값이 없습니다.
하지만, 괄호 안의 선택자 목록의 선택자에는 영향을 끼칩니다.
:has()
자체
:has()
선택자는 자체적으로 구체성 값이 없으며, 단지 선택자를 그룹화하는 역할만 합니다. 따라서, :has()
자체는 구체성을 결정하지 않습니다.
괄호()
안의 형제, 자손 관계 선택자 목록
:has()
선택자의 괄호 안에 나열된 형제, 자손 관계 선택자 목록에서는 각 선택자가 해당 요소를 선택하는 구체성 값에 영향을 미칩니다.
구체성 값은 :has()
괄호 안에서 나열된 형제, 자손 관계 선택자 목록 중 가장 구체성 값이 높은 형제, 자손 관계 선택자의 값을 따르게 됩니다. 이때, 나머지 목록의 선택자들에게도 동일하게 적용됩니다. 다음의 예제와 관련 설명을 참조하세요.
예제를 통한 설명
<section class="container">
<h4 id="heading">나는 h4 요소입니다.</h4>
<p>나는 p 요소입니다.</p>
</section>
section:has(#heading, p) {
background-color: gold;
}
.container {
background-color: blue;
}
나는 h4 요소입니다.
나는 p 요소입니다.
section:has(#heading, p)
선택자는#heading
(id
속성의 값이heading
인<h4>
요소)과p
(class
속성의 값이paragraph
인<p>
요소)를 가지고 있는section
요소에 대해 배경색을gold
로 설정합니다. 구체성 값을 결정하는#heading
과p
선택자의 구체성 값 차이가 중요합니다.#heading
의 구체성 값은#heading
이id
를 사용하는 선택자로 구체성 값이 매우 높은 0,1,0,0입니다.p
의 구체성 값은p
가 요소 이름 선택자이기 때문에 구체성 값이 낮은 0,0,1,0입니다.- 이때, 괄호 안에서 나열된 선택자 목록 중 가장 구체성 값이 높은 선택자의 값을 따르게 됩니다. 즉,
p
의 구체성 값은 자체적으로 구체성 값이 낮지만 괄호 안에서 가장 구체성 값이 높은#heading
의 구체성 값(0, 1,0,0)을 가지게 됩니다. 따라서,section:has(#heading, p)
전체의 구체성 값은section
의 구체성 값인 0,0,0,1을 포함하여 0,1,0,1이 됩니다. background-color: blue
를 지정한.container
선택자의 구체성 값은 0.0.1.0이므로, 이보다 더 높은 구체성 값(0, 1,0,1)을 가지는section:has(#heading, p)
로 지정한background-color: gold
가 적용되는 것입니다.
주의할 점
:has()
함수형 가상 클래스를 사용할 때 형제, 자손 관계 선택자 목록 중 사용할 수 없는 선택자가 있습니다.
:has()
의 괄호 안의 선택자 목록에는 가상 요소 선택자(예:::before
,::after
,::marker
,::placeholder
,::selection
등)를 사용할 수 없습니다.:has()
의 괄호 안의 선택자 목록에는 또 다른:has()
을 중첩(예::has(:has(div))
)해서 사용할 수 없습니다.
브라우저 호환성
선택자 |
데스크탑 Chrome
|
데스크탑데스크탑 Edge
|
데스크탑 Firefox
|
Safari
|
---|---|---|---|---|
:has()
|
105 | 105 | 121 | 15.4 |
명세서
명세서 사양 | |
---|---|
:has()
|
Selectors Level 4 #relational |