:where() CSS pseudo selector

Published at 2024. 5. 19.

7 min read

#CSS

Table of Contents

๋“ค์–ด๊ฐ€๊ธฐ ์ „์—

๋‹ค์Œ์˜ ์งง์€ HTML, CSS code ๋ฅผ ๋ณด๊ณ  ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฅผ ์˜ˆ์ธกํ•ด๋ณด์ž. MDN์—์„œ ๊ฐ€์ ธ์˜จ ์˜ˆ์ œ๋‹ค.

<ol>
	<li>Saturn</li>
	<li>
		<ul>
			<li>Mimas</li>
			<li>Enceladus</li>
			<li>
				<ol>
					<li>Voyager</li>
					<li>Cassini</li>
				</ol>
			</li>
			<li>Tethys</li>
		</ul>
	</li>
	<li>Uranus</li>
	<li>
		<ol>
			<li>Titania</li>
			<li>Oberon</li>
		</ol>
	</li>
</ol>
ol {
	list-style-type: upper-alpha;
	color: darkblue;
}

:where(ol, ul, ul:unsupported) :where(ol, ul) {
	color: green;
}

:where(ol, ul) :where(ol, ul) ol {
	list-style-type: lower-greek;
	color: chocolate;
}

๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

example code

๋งค์šฐ ๊ฐ„๋‹จํ•ด ๋ณด์ด๋Š” ์˜ˆ์ œ์ง€๋งŒ, :where() ์„ ์ฒ˜์Œ ๋งˆ์ฃผํ•œ๋‹ค๋ฉด ํ˜ผ๋ž€์Šค๋Ÿฌ์šธ ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ์ œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด MDN์˜ ์„ค๋ช…๋ถ€ํ„ฐ ๋“ค์—ฌ๋‹ค๋ณด์ž.

:where()

๋งˆ์น˜ SQL query ๋ฌธ์— ์“ฐ์ด๋Š” WHERE ๊ฐ™์€ ๋Š๋‚Œ์„ ์ค€๋‹ค. MDN์„ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ ํ˜€์žˆ๋‹ค.

The :where() CSS pseudo-class function takes a selector list as its argument, and selects any element that can be selected by one of the selectors in that list. The difference between :where() and :is() is that :where() always has 0 specificity, whereas :is() takes on the specificity of the most specific selector in its arguments.

:where() ๊ณผ :is() ์˜ ์ฐจ์ด์ ์— ๊ด€ํ•œ ์–ธ๊ธ‰, CSS specificity ์— ๊ด€ํ•œ ์–ธ๊ธ‰์ด ๋ˆˆ์— ๋ˆ๋‹ค. ์šฐ์„ , :where() selector ์˜ ์—ญํ• ์€ ํ•ด๋‹น selector ์˜ ์ธ์ž๋กœ ์ฃผ์–ด์ง„ selector list ๋“ค ์ค‘์— ํ•˜๋‚˜๋ผ๋„ ๋งž๋Š”๊ฒŒ ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์„ค๋ช…๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ๋‚ด๊ฐ€ ์‹ค์ œ๋กœ Open Props ์˜ style์„ override ํ•ด์•ผ ํ–ˆ๋˜ ๊ฒฝ์šฐ๋ฅผ ๊ฐ€์ ธ์™€ ๋ดค๋‹ค.

/* Open Props ์˜ visited anchor tag ์— ๋Œ€ํ•œ default style */
:where(a):where([href]):where(:visited) {
	color: var(--brand);
	text-decoration-color: var(--brand);
}

/* ์œ„์˜ selector ๋Œ€์‹  ๋‹ค์Œ์ฒ˜๋Ÿผ ์ž‘์„ฑํ•ด๋„ ๋™์ผํ•˜๋‹ค */
a[href]:visited {
	color: var(--brand);
	text-decoration-color: var(--brand);
}

MDN์˜ ์„ค๋ช…์ฒ˜๋Ÿผ :where() selector ๋Š” ์ธ์ž๋กœ ์ฃผ์–ด์ง„ selector list ์ค‘์— ํ•˜๋‚˜๋ผ๋„ ์ผ์น˜ํ•˜๋ฉด ๊ทธ ์š”์†Œ๋ฅผ ์„ ํƒํ•œ๋‹ค. ์œ„์˜ ์˜ˆ์ œ์—์„œ๋Š” a ํƒœ๊ทธ์ด๋ฉด์„œ href attribute ๊ฐ€ ์กด์žฌํ•˜๊ณ  :visited pseudo class ๋ฅผ ๋งŒ์กฑํ•˜๋Š” ์š”์†Œ๋ฅผ ์„ ํƒํ•œ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๋‘˜ ์‚ฌ์ด์—๋Š” ์š”์†Œ ์„ ํƒ์˜ ๋ฐฉ์‹ ์ด์™ธ์— ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ผ๊นŒ?

๋‚ด๊ฐ€ ์ƒ๊ฐํ•˜๊ธฐ์— ํ•ต์‹ฌ์€ CSS specificity ์— ์žˆ๋‹ค. :where() pseudo selector ๋Š” specificity ๊ฐ€ 0 ์ด๋‹ค. ์ฆ‰, :where(a):where([href]):where(:visited) ๋ผ๋Š” selector ์˜ specificity ๋Š” 0์œผ๋กœ ๊ณ„์‚ฐ์ด ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. Specificity ๊ฐ€ 0์ด๋ผ๋Š” ๊ฒƒ์€, ํ•ด๋‹น selector ๋ฅผ ๋‹ค๋ฅธ selector ๋กœ ์‰ฝ๊ฒŒ ๋ฎ์–ด์“ธ ์ˆ˜(override) ์žˆ๋‹ค๋Š” ๋œป์ด๋‹ค.

๊ทธ๋ž˜์„œ ์ถ”์ธก์ปจ๋Œ€, Open Props ์—์„œ๋Š” ๋ณธ์ธ๋“ค์˜ ๋””์ž์ธ ์‹œ์Šคํ…œ์„ ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ๊ฐœ๋ฐœ์ž๋“ค์ด !important ๋ฅผ ์“ฐ์ง€ ์•Š๊ณ ๋„ ์†์‰ฝ๊ฒŒ default style ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก :where() ์„ ํ—ค๋น„ํ•˜๊ฒŒ ์‚ฌ์šฉํ•œ ๊ฒƒ์ด ์•„๋‹Œ๊ฐ€ ์‹ถ๋‹ค.

MDN ์˜ˆ์ œ ์ดํ•ด

๊ทธ๋Ÿผ ๋‹ค์‹œ MDN ์˜ˆ์ œ๋กœ ๋Œ์•„์™€์„œ ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฌผ์„ ์ดํ•ดํ•ด๋ณด์ž.

CSS ๋ฅผ ํ•œ ๋ถ€๋ถ„์”ฉ ์‚ดํŽด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ์„ค๋ช…์˜ ํŽธ์˜๋ฅผ ์œ„ํ•ด ๊ฐ CSS selector ์— ๋ฒˆํ˜ธ๋ฅผ ๋ถ™์˜€๋‹ค.

/* 1๋ฒˆ */
/* ol tag selector => specificity ๋Š” (0, 0, 1) */
ol {
	list-style-type: upper-alpha;
	color: darkblue;
}

/* 2๋ฒˆ */
/* ol, ul, ul:unsupported ๋‚ด๋ถ€์— ์กด์žฌํ•˜๋Š” ๋ชจ๋“  ol, ul tag ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” selector => specificity ๋Š” (0, 0, 0) */
/* (ol ol), (ol ul), (ul ol), (ul ul) ์ผ€์ด์Šค๋ฅผ ๋ชจ๋‘ ์•„์šฐ๋ฅธ๋‹ค */
/* ul:unsupported ๋Š” ๋‹ค์Œ ์„น์…˜์—์„œ ๋‹ค๋ฃฌ๋‹ค */
:where(ol, ul, ul:unsupported) :where(ol, ul) {
	color: green;
}

/* 3๋ฒˆ */
/* ol, ul ์•ˆ์˜ ol, ul ์•ˆ์˜ ol tag ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” selector => specificity ๋Š” (0, 0, 1) */
/* (ol ol ol), (ol ul ol), (ul ol ol), (ul ul ol) ์ผ€์ด์Šค๋ฅผ ๋ชจ๋‘ ์•„์šฐ๋ฅธ๋‹ค */
:where(ol, ul) :where(ol, ul) ol {
	list-style-type: lower-greek;
	color: chocolate;
}

์ด์ œ ๊ฒฐ๊ณผ๋ฌผ์„ ๋ณด๋ฉด์„œ ํ•œ ๋ถ€๋ถ„์”ฉ ์ดํ•ดํ•ด๋ณด์ž.

example code
  1. 1๋ฒˆ selector ์— ์˜ํ•ด Saturn, Uranus, Titania, Oberon ์˜ font color ๋Š” darkblue ๊ฐ€ ๋œ๋‹ค.
  2. 2๋ฒˆ selector ์— ์˜ํ•ด Mimas, Enceladus, Tethys ์˜ font color ๋Š” green ์ด ๋œ๋‹ค.
  3. 3๋ฒˆ selector ์— ์˜ํ•ด Voyager, Cassini ์˜ font color ๋Š” chocolate ์ด ๋œ๋‹ค.
    1๋ฒˆ selector ์™€ ์ถฉ๋Œ์ด ์ƒ๊ธฐ์ง€๋งŒ 1๋ฒˆ, 3๋ฒˆ selector ์˜ specificity ๋ชจ๋‘ (0, 0, 1) ์ด๋ฏ€๋กœ ๋” ๋‚˜์ค‘์— ์„ ์–ธ๋œ 3๋ฒˆ selector ์˜ ์Šคํƒ€์ผ๋กœ ๋ฎ์–ด์”Œ์›Œ์ง„๋‹ค.
    ์‹ค์ œ๋กœ 3๋ฒˆ selector ๋ฅผ 1๋ฒˆ selector ๋ณด๋‹ค ๋จผ์ € ์„ ์–ธํ•˜์—ฌ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋ฉด Voyager, Cassini ์˜ font color ๊ฐ€ darkblue ๊ฐ€ ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Forgiving Selector Parsing

:where() pseudo selector ์— ๊ด€ํ•ด ์•Œ์•„๋ณด๋ฉด์„œ ์ถ”๊ฐ€์ ์œผ๋กœ ์•Œ๊ฒŒ๋œ ๋ถ€๋ถ„์ด ์žˆ๋Š”๋ฐ, Forgiving Selector Parsing ์ด๋ผ๋Š” ๊ฐœ๋…์ด๋‹ค.

์ด ๊ฐœ๋…์€ :where() ๊ณผ :is() pseudo selector ์—๋งŒ ์กด์žฌํ•˜๋Š” ๊ฐœ๋…์ด๋‹ค. ์–ด๋ ค์šธ ๊ฒƒ์€ ์—†๋‹ค.
:where() ๊ณผ :is() ์— ์ธ์ž๋กœ selector list ๋ฅผ ์ „๋‹ฌํ•ด์คฌ์„ ๋•Œ, ์œ ํšจํ•˜์ง€ ์•Š์€(invalid) selector ๊ฐ€ ์„ž์—ฌ์žˆ๋”๋ผ๋„ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค.

/* ์•„๋ž˜์ฒ˜๋Ÿผ ์ž‘์„ฑํ•˜๋ฉด ':unsupported' pseudo class ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ์ „์ฒด selector ๊ฐ€ ๋จนํ†ต์ด ๋œ๋‹ค. */
/* ์ฆ‰, :valid ์— ๋Œ€ํ•œ selector ๋„ ๊ฐ™์ด ๋ฌด์‹œ๋œ๋‹ค */
:valid,
:unsupported {
	/* โ€ฆ */
}
/* ํ•˜์ง€๋งŒ ์•„๋ž˜์ฒ˜๋Ÿผ ์ž‘์„ฑํ•˜๋ฉด ':unsupported' pseudo class ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋ผ์šฐ์ €๋ผ๋„ ':valid' ์— ๋Œ€ํ•œ selector ๋Š” ๋™์ž‘ํ•œ๋‹ค */
:where(:valid, :unsupported) {
	/* โ€ฆ */
}

Slow But Steady ยฉ 2024