๐ CSS ์ ํ์๋ฅผ ๋ชจ๋ํ๊ฒ :where() / :is() / :has() / :not()
:where() ๊ฐ์ ์ ํ์
:where ์์ฌ ํด๋์ค ์ ํ์๋ css ์ฝ๋ฉํ ๋ ์ ํ์์ ์ค๋ณต์ ์ค์ด๋ ๋ฐ ๋์์ด ๋๋ ๋
์์ด๋ค.
์๋ฅผ๋ค์ด ๋ค์๊ณผ ๊ฐ์ด ์ฌ๋ฌ ์๋ฆฌ๋จผํธ ์์ ์๋ anchor ํ๊ทธ์ hover ํจ๊ณผ๋ฅผ ์ฃผ๊ธฐ์ํด์ ๊ฐ ์ ํ์๋ค์ ์ฝค๋ง๋ฅผ ์ด์ด ๋์ดํ์ฌ ํํํ์ฌ์ผ ํ์๋ค.
<nav>
<ul>
<a href="#">element 1</a>
</ul>
</nav>
<footer>
<ol>
<a href="#">element 2</a>
</ol>
</footer>
<aside>
<p>
<a href="#">element 3</a>
</p>
</aside>
nav > ul a:hover,
footer > ol a:hover,
aside > p a:hover {
color: purple;
text-decoration: underline wavy deeppink;
}
๊ทธ๋ฐ๋ฐ ์ฝ๋๋ฅผ ๋ณด๋ฉด a:hover ๋ถ๋ถ์ด ๊ฐ ์ ํ์๋ง๋ค ์ค๋ณต๋๋ ๊ฒ์ ํ์ธ ํ ์ ์์ ๊ฒ์ด๋ค. ๊ฑฐ๊ธฐ๋ค ์ ์ฉํด์ผํ ์์๊ฐ ๋ง์ผ๋ฉด ๋ง์ ์๋ก ์ ํ์์ ์๋ ๋์ด๋ ๋์ค์ ๊ฐ๋
์ฑ ๋ฐ ์ ์ง๋ณด์๋ ํ๋ค์ด์ง๊ฒ ๋๋ฉฐ, ๋ง์ผ ์ผํ๋ก ์ด์ด์ง ์ด๋ค ์ ํ์์ค ํ๋๊ฐ ์๋ชป๋๋ฉด ์ ์ฒด๊ฐ ์ ์ฉ๋์ด์ง์ง ์๋ ๋ฌธ์ ์ ์ด ์๊ธฐ๊ฒ ๋๋ค.
:where() ์ฌ์ฉ๋ฒ
์ด๋ :where() ์ ํ์๋ฅผ ํตํด ๋ณด๋ค ๋ชจ๋์ค๋ฝ๊ฒ css ์ฝ๋๋ฅผ ๊ตฌ์ฑํ ์ ์๋ค. ๋ถํ์ํ ์ค๋ณต์ ์์ ์ฝ๋ ์์ฒด๋ ์งง์์ง๊ฒ ๋๊ณ , ๊ฐ ์ ํ์๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ๋ถ์ํ๊ธฐ ๋๋ฌธ์ ๋ง์ผ ์๋ชป๋ ์ ํ์๊ฐ ์์ด๋ ์ดํด๊ฐ ์๋๋ฉด ๊ทธ๋๋ก ๋ฒ๋ ค๋ฒ๋ ค ํ์ฅ์ฑ๋ ์ข๋ค.
:where(nav > ul, footer > ol, aside > p) a:hover {
color: purple;
text-decoration: underline wavy deeppink;
}
See the Pen :where ์ ํ์ by barzz12 (@inpaSkyrim) on CodePen.
์ด์ค :where() ์ฒ๋ฆฌ
์ข ๋ ์ด ์ ํ์์ ๊ฐ๋ ฅํ ํจ๊ณผ๋ฅผ ํ์ฐํ ๋๋์ ์๊ฒ ์ข ๊ธธ๋ค๋ ์์ ์ฝ๋๋ฅผ ๊ฐ์ ธ์๋ดค๋ค.
๋ค์ ์ ํ์๋ค์ ๋ณด๋ฉด section, article, aside, nav ์ ํ์์ ๊ทธ์ ์์์ธ h1 ~ h6 ์ ํ์๊ฐ ๋ฐ๋ณต๋๋ ๊ฑธ ๋ณผ ์ ์๋ค. ์ด๋ฅผ ์ด์ค :where() ์ ํตํด ํ๊ธฐ์ ์ผ๋ก ์ค์ผ ์๊ฐ ์๋ค.
section h1, section h2, section h3, section h4, section h5, section h6,
article h1, article h2, article h3, article h4, article h5, article h6,
aside h1, aside h2, aside h3, aside h4, aside h5, aside h6,
nav h1, nav h2, nav h3, nav h4, nav h5, nav h6 {
color: #BADA55;
}
/* ↓ */
:where(section, article, aside, nav) :where(h1, h2, h3, h4, h5, h6) {
color: #BADA55;
}
:where() ํ๊ณ์
๋ค๋ง ::before ๋ ::after ์ ๊ฐ์ ์์ฌ ์์๋ DOM์ ์๋ ์์๊ฐ ์๋๋ฏ๋ก ์ ํ์ด ๋ถ๊ฐ๋ฅํด ๋ฌถ์์ ์๋ค๋ ํ๊ณ๊ฐ ์๋ค.
/* ๋์ํ์ง ์์ */
a:where(::before, ::after) {
...
}
/* ์ด์ฉ์ ์์ด ์ผํ๋ก ์ด์ด์ผ ํ๋ค */
a::before,
a::after {
...
}
:is() ๊ฐ์ ์ ํ์
์ด ์ ํ์๋ ์์์ ๋ฐฐ์ด :where ์ ํ์์ ๋์ผํ๊ฒ ๋์๋๋ค.
๋จ, ์ ์ผํ ์ฐจ์ด์ ์ ๋ช
์๋ ์ ์๋ค. id ์ ํ์๋ ๋ค๋ฅธ ์ ํ์๋ณด๋ค ์ฐ์ ์์๊ฐ ๊ฐ์ฅ ๋๊ณ , css ์ฝ๋๊ฐ ์๋์ผ ์๋ก ์ฐ์ ์์๊ฐ ์ ์ฉ๋๋ค๊ณ ๋ค์ด๋ณธ์ ์ด ์์ ๊ฒ์ธ๋ฐ ์ด๊ฒ์ ๋งํ๋ ๊ฒ์ด๋ค. ์ฆ, :where()๋ ๋ช
์๋๊ฐ 0์ด์ง๋ง :is()๋ ๋ช
์๋๊ฐ ๊ฐ์ฅ ๋๋ค.
:where()์ :is() ์ฐจ์ด์
์๋ ์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด <header> , <main> , <footer> ์์ ๊ธ์์ ์์ ์คํ์ผ๋ง ํ๋ ค ํ๋ค. ์ด๋ ๊ฐ๊ฐ :where() ์ :is() ๋ก ๊ธ์์์ ์ง์ ํ๊ณ css ๋ง์ง๋ง์ ์ ์ฒด ์ ํ์๋ก ๊ธ์์์ ๋
น์์ผ๋ก ๋ฎ์ด ์์ ๋ค. ๊ฒฐ๊ณผ๋ ์ด๋ป๊ฒ ๋ ๊น?
<article>
<h2>:where()</h2>
<header class="where">
<p>Section</p>
</header>
<main class="where">
<p>Aside</p>
<main/>
<footer class="where">
<p>Footer</p>
</footer>
</article>
<article>
<h2>:is()</h2>
<header class="is">
<p>Section</p>
</header>
<main class="is">
<p>Aside</p>
</main>
<footer class="is">
<p>Footer</p>
</footer>
</article>
/* ๋งจ ์๋ ์ ์๋ ์ ํ์์ ์ํด ๋ฌด์๋๋ค */
:where(header.where, main.where, footer.where) p {
color: red;
}
/* ๊ฐ์ฅ ๋ช
์๋๊ฐ ๋์ ๋ฐ์ ๋ญ๊ฐ ์๋ ๋ฌด์กฐ๊ฑด ์ ์ฉ๋๋ค */
:is(header.is, main.is, footer.is) p {
color: orange;
}
/* ์ ์ฒด ์ ํ์ ์ฒ๋ฆฌ */
header p,
main p,
footer p {
color: green;
}
See the Pen :is() ์ ํ์ by barzz12 (@inpaSkyrim) on CodePen.
:where() ์ ๋ช
์๋๊ฐ 0์ด๊ธฐ ๋๋ฌธ์ css ๋ง์ง๋ง์ ์ ์ธ๋ ์ ์ฒด ์ ํ์์ ์ํด ํจ๊ณผ๊ฐ ๋ฎ์ด์์์ก๋ค. ๊ทธ๋ฌ๋ :is()๋ ๋ช
์๋๊ฐ ๋์ ๊ฐ์ฅ ๋์ ์ฐ์ ์์๋ฅผ ๊ฐ์ง๊ธฐ ๋๋ฌธ์ ๋ค์ ๋ญ๊ฐ ์ค๋ ๋ฌด์กฐ๊ฑด ํด๋น ์คํ์ผ๋ก ์ ์ฉ๋๊ฒ ๋๋ค.
:not() ๊ฐ์ ์ ํ์
์ด ์ ํ์๋ ์ด๋ฆ ๊ทธ๋๋ก :not() ๊ดํธ ์์ ๋งค๊ฐ๋ณ์ ์์๋ฅผ ์ ์ธํ ๋ชจ๋ ์์์ ์คํ์ผ์ ์ง์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
:not() ์ ์ด์ฉํ๋ฉด ์๋ฃจ์
์ ๋ํด์ ์ข๋ ์ฌํํ๊ฒ ํด๊ฒฐ์ฑ
์ ๊ตฌ์ฑํ ์ ๊ฐ ์๋๋ฐ, ์๋ฅผ ๋ค์ด ๋ค์ ๋ฆฌ์คํธ ๋ฐ์ค ๋ง๋ค ๊ฐ๊ฒฉ์ ์ฃผ๊ธฐ ์ํด margin-bottom์ ์ค์ ํ์๋ค๊ณ ํ์.
<div class="card">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</div>
ul li {
margin-bottom: 20px;
}
See the Pen :not ์ ํ์ by barzz12 (@inpaSkyrim) on CodePen.
ํ์ง๋ง ๋ชจ๋ ๋ฆฌ์คํธ ํ๋จ์ margin์ด ๋ค์ด๊ฐ ๋ฐ์ค๊ฐ ๋์นญ์ด ์ด๋ฃจ์ด์ง์ง ์๋ ๋ฌธ์ ์ ์ด ์๋ค.
margin-top๋ ์ค์ ํ๋ ๋ฒ์ด๋ ๊ฐ์ ๋ก li ์์ ๋ง์ง๋ง์ margin์ ์ค์ ํ์ง ์๋๋ก ํ๋ ๋ฐฉ๋ฒ๋ ์๊ฒ ์ง๋ง ์ข๋ ์ฌํํ๊ณ ์ฝ๋ ํ์ค๋ก ํด๊ฒฐํ ์๊ฐ ์๋ค.
/* li ์์ ๋ง์ง๋ง์ ์ ์ฉํ์ง ์๋๋ค */
ul li:not(:last-of-type) {
margin-bottom: 20px;
}
See the Pen Untitled by barzz12 (@inpaSkyrim) on CodePen.
์ด๋ฐ์๋ ์ด๋ฅผ ์์ฉํด ์์ฑ ์ ํ์์์ ์ง์์ํ๋ != not equals ์ฐ์ฐ์ ๊ธฐ๋ฅ์ ๊ตฌํํ ์๋ ์๋ค.
:has() ๊ฐ์ ์ ํ์
:has() ๋ ์ต๊ทผ์ ์ถ๊ฐ๋ ์ ํ์์ด๋ค. ์ด ์ ํ์๋ ํด๋น ๋ถ๋ชจ ์ ํ์๊ฐ ํน์ ์์ ์ ํ์๋ฅผ ๊ฐ์ง๊ณ ์์ ๊ฒฝ์ฐ ์ ์ฉํ๋ ์ด๋ฅธ๋ฐ css์ if๋ฌธ ๋ฒ์ ์ด๋ผ ๋ณด๋ฉด ๋๋ค. ๊ธฐ์กด์๋ ์ด๋ฅผ ๊ตฌํํ๋ ค๋ฉด css๋ก๋ง์ ๋ฌธ๋ฒ์ ์ธ ํ๊ณ๊ฐ ์์ด์ SCSS๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ํตํด์๋ง ๊ฐ๋ฅํ๋ค. ํ์ง๋ง :has() ๊ฐ๋
์ ๊ต์ฅํ ์ ์ฉํ๊ณ ํธ๋ฆฌํ ์ ํ์ ๊ฐ๋
์ด๋ผ jQuery์์ ์ ์ด์ฟผ๋ฆฌ ์ ์ฉ ์ ํ์์ผ๋ก๋ง ์ฐ์์ง๋ง, ์ผ๋ง์ ๋๋์ด ๊ณต์ํ ๋์๋ค.
์ฌ์ฉ๋ฒ์ ์๋ฅผ๋ค์ด div.parent ๊ฐ ๋ง์ผ p ์์๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฒฝ์ฐ์๋ง ์์ ์ ์์์ ์คํ์ผ์ ์ ์ฉํ๊ณ ์ถ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
<div class="parent">
<p>Child</p>
</div>
/* div ์์๊ฐ ์์์ผ๋ก p๋ฅผ ๊ฐ์ง๊ณ ์์ ๊ฒฝ์ฐ ์คํ์ผ ์ ์ฉ */
div:has(> p) {
background: red;
}
:has() ์ ํ์ ์กฐํฉ ์ข ๋ฅ
:has() ๊ดํธ ์ ๋งค๊ฐ๋ณ์๋ก ์ ํ์ ๋ฌธ๋ฒ์ ๋ฃ์์ผ๋ก์จ ์์, ํ์ , ์์ ์ ํ์๋ฅผ ๋ค์ํ ํญ์ผ๋ก ์ง์ ํด์ค ์ ์๋ค.
/* a ์์๊ฐ ์์์ผ๋ก img๋ฅผ ๊ฐ์ง๊ณ ์์ ๊ฒฝ์ฐ */
a:has(img) {
}
/* a ์์๊ฐ ์์์ผ๋ก img๋ฅผ ๊ฐ์ง๊ณ ์์ ๊ฒฝ์ฐ */
a:has(> img) {
}
/* h3 ์์๊ฐ ํ์ ๋ก p๋ฅผ ๊ฐ์ง๊ณ ์์ ๊ฒฝ์ฐ */
h3:has(+ p) {
}
/* article ์์๊ฐ ์์์ผ๋ก h3 ๊ทธ๋ฆฌ๊ณ p๋ฅผ ๊ฐ์ง๊ณ ์์ ๊ฒฝ์ฐ (and ๋
ผ๋ฆฌ) */
article:has(h3, p) {
}
:has() ์ :not() ์กฐํฉ
์ด๋ฒ์ ์ฝ๊ฐ ๋์ด๋ ๋์ ์กฐํฉ์ ๊ฐ์ ธ์ ๋ณด์๋ค. :has() ์ :not() ๊ฐ์ ์์๋ฅผ ์ด๋ค ์์๋๋ก ์กฐํฉํ๋๋์ ๋ฐ๋ผ ๋
ผ๋ฆฌ์ ์ผ๋ก ์์ ํ ๋ฌ๋ผ์ง๊ธฐ ๋๋ฌธ์, ์ด๋ป๊ฒ ๋๋์ง ์ฝ๋๋ฅผ ๋ณด๊ณ ์ถ๋ก ํด๋ณด์.
/* div ์์๊ฐ ์์์ผ๋ก h3์ ๊ฐ์ง๊ณ ์์ง ์์ ๊ฒฝ์ฐ ์ ์ฒด ์นผ๋ผ ์ ์ฉ */
div.section1:not(:has(h3)) {
color: red;
}
/* div ์์์ ์์์ด h3์ด ์๋ ์์๊ฐ ์์ ๊ฒฝ์ฐ ์ ์ฒด ์นผ๋ผ ์ ์ฉ */
div.section2:has(:not(h3)) {
color: blue;
}
See the Pen :has() ์ :not() ์กฐํฉ by barzz12 (@inpaSkyrim) on CodePen.
์๋ฐ์คํฌ๋ฆฝํธ ์ ๋ ํฐ ์กฐํฉ
:has() ์ ํ์๋ ์คํฌ๋ฆฝํธ๋ก ๋์ ์ผ๋ก ์์๋ฅผ ์กฐ์ํด์ผ ํ ๋ ๋น์ ๋ฐํ๋ค.
์๋ฅผ๋ค์ด div.parent ๊ฐ ๋ง์ผ p ์์๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฒฝ์ฐ์๋ง ์๋ฆฌ๋จผํธ๋ฅผ ๊ฐ์ ธ์ค๊ณ ์ถ๋ค๋ฉด, ๊ธฐ์กด์๋ child ์์๋ฅผ ์ผ์ผํ ์ํํด์ ํ์ํ๋ฉฐ ๋ถ๊ฐํด์ผ ๋ฌ์ง๋ง, ์ด selector ํ๋๋ก ๊ณง๋ฐ๋ก ์ผ์นํ๋ ์์๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๊ฒ ๋์๋ค.
<div class="parent">
<input type="checkbox" />
<p>Child</p>
</div>
<div class="parent">
<input type="radio" />
<p>Child</p>
</div>
<div class="parent">
<p>Child</p>
</div>
document.querySelectorAll('.parent:has(p)')
/* ์ ์ด์ฟผ๋ฆฌ๋ ์์ฒด ์ง์ํ๋ค. */
$('.parent:has(p)')
๋ธ๋ผ์ฐ์ ๊ฐ :has() ๋ฅผ ์ง์ํ๋์ง ํ ์คํธ
๋จ, ์ต์ ์คํ์ธ ๋งํผ ์์ง ํ์ด์ดํญ์ค๋ ์ธํฐ๋ท ์ต์คํ๋ก๋ฌ์์๋ ์์ง ์ฌ์ฉํ ์ ์๋ค๋ ๋จ์ ์ด ์๋ค.
๋ง์ผ ํด๋น ๋ธ๋ผ์ฐ์ ๊ฐ ์ด ์ ํ์๋ฅผ ์ง์ํ๋์ง ์์๋ณด๊ณ ์ฐํ ๋ฐฉ๋ฒ์ ์ ์ฉํ๊ณ ์ถ๋ค๋ฉด @supports ๋ฅผ ํตํด ๊ตฌ์ฑํด์ฃผ๋ฉด ๋๋ค.
@supports(selector(:has(p))) {
/* Supported! */
}
@supports not (selector(:has(p))) {
/* Not Supported! ์ฐํ์ฝ๋ ์์ฑ */
}
# ์ฐธ๊ณ ์๋ฃ
https://junghan92.medium.com/%EB%B2%88%EC%97%AD-where-is-has-%EB%8B%B9%EC%8B%A0%EC%9D%98-%EC%82%B6%EC%9D%84-%EB%8D%94-%EC%89%BD%EA%B2%8C-%EB%A7%8C%EB%93%A4%EC%96%B4-%EC%A4%84-%EC%83%88%EB%A1%9C%EC%9A%B4-css-%EC%84%A0%ED%83%9D%EC%9E%90-ee44dd58aa3b
https://css-tricks.com/complete-guide-to-css-functions/