CSS:has(.parent ์„ ํƒ๊ธฐ)๐Ÿ‘ช

6584 ๋‹จ์–ด webdevcsstodayilearnedjavascript
๋‚˜๋Š” ์™œ ๋‚ด๊ฐ€'๊ณผํ•™๊ธฐ์ˆ  ํŠธ์œ„ํ„ฐ'์— ๊ด€์‹ฌ์„ ๊ฐ€์ง€๊ณ  ์ข‹์€ ์†Œ์‹์„ ์•Œ์•„์•ผ ํ•˜๋Š”์ง€ ์•Œ๊ณ  ์‹ถ์–ด์„œ dev.์— ์ƒˆ๋กœ์šด CSS ๊ธฐ๋Šฅ์„ ์ถ•ํ•˜ํ•˜๋Š” ์งง์€ ๊ธ€์„ ์ผ๋‹ค.
State of CSS survey 2021์˜ ํ†ต๊ณ„์— ๋”ฐ๋ฅด๋ฉด ๋‘ ๋ฒˆ์งธ๋กœ ๊ธฐ๋Œ€๋˜๋Š” CSS ๊ธฐ๋Šฅ์ธ'๋ถ€๋ชจ ์„ ํƒ๊ธฐ'(Parent selectors)๋Š”has ์„ ํƒ๊ธฐ๋ผ๊ณ ๋„ ๋ถˆ๋ฆฌ๋ฉฐ ๋ธŒ๋ผ์šฐ์ € ์ง€์›์„ ๋ฐ›์•˜๋‹ค!
์‚ฌ๋ผ ์ˆ˜์—๋‹จ์„ ์ธ์šฉํ•ด ํŠธ์œ„ํ„ฐ์— ์ž” ์‹œ๋ชฌ์Šค์˜ ๋ง์„ ์ธ์šฉํ•œ๋‹ค.

:has() is essentially the long-awaited parent selector in CSS ๐ŸŽŠ

Donโ€™t say Safari is always last. Sometimes we are first.


๊ทธ๋Ÿฌ๋‚˜ ์ด๋ฒˆ'Safari first'๋ฅผ ์ถ•ํ•˜ํ•˜๊ธฐ ์ „์— 2022๋…„ ์ดˆ์— ํ•™๋ถ€๋ชจ ์„ ํƒ๊ธฐ๋ฅผ ํ…Œ์ŠคํŠธํ•  ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์—†์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.์‚ฌํŒŒ๋ฆฌ๋Š” ํ˜„์žฌ ์—…๋ฐ์ดํŠธ ์ค‘์ž…๋‹ˆ๋‹ค.

CSS์—์„œ ๋” ์ด์ƒ ์‚ฌ๋ผ์ง€์ง€ ์•Š์Œ


ํ˜„์žฌ CSS์—๋Š” ๋ถ€๋ชจ ์„ ํƒ๊ธฐ๊ฐ€ ๋” ์ด์ƒ ๋ถ€์กฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Firefox์™€ Chromium์ด ๋นจ๋ฆฌ ๋”ฐ๋ผ๊ฐ€๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๋ถ€๋ชจ ์„ ํƒ๊ธฐ๋Š” ๋ฌด์—‡์„ ์„ ํƒํ•ฉ๋‹ˆ๊นŒ?


๋ถ€๋ชจ ์„ ํƒ๊ธฐ์—์„œ ๋ถ€๋ชจ ์š”์†Œ๋ฅผ ์„ ํƒํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?๊ทธ๋“ค์€ ์‹ค์ œ๋กœ๋„ ์กฐ๋ถ€๋ชจ์™€ ์ผ์น˜ํ•˜๋Š” ์กฐ์ƒ์„ ์„ ํƒํ•  ๊ฒƒ์ด๋‹ค.
๋‚˜๋Š” ์œ ์ผํ•˜๊ฒŒ :has()๊ฐ€'์–ด๋ฆฐ์ด ์„ ํƒ๊ธฐ'๋ผ๊ณ  ์ƒ๊ฐํ•˜๋Š” ์‚ฌ๋žŒ์ด ์•„๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚˜๋Š” ๊ทธ๋“ค์„'has ์„ ํƒ๊ธฐ'๋ผ๊ณ  ๋ถˆ๋Ÿฌ์„œ ์˜คํ•ด๋ฅผ ํ”ผํ•ด์•ผ ํ•˜๋Š”๊ฐ€?
๋‚˜์—๊ฒŒ ์žˆ์–ด์„œ ์ด๊ฒƒ์€ ๋“ฃ๊ธฐ์— ์ ๋‹นํ•œ ๋ฌ˜์‚ฌ์ด๋‹ค.
์‹œ์ž‘caniuse.com/css-has:

For example, a:has(>img) selects all <a> elements that contain an <img> child.


The :has() CSS pseudo-class is documented well on MDN .

์„ฑ๋Šฅ ๊ณ ๋ ค ์‚ฌํ•ญ


์ด ๊ณ„ํš์„ ์‹ค์‹œํ•˜๋Š” ๋ฐ ์ด๋ ‡๊ฒŒ ๋งŽ์€ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ๋Š”๋ฐ, ์ฃผ์š” ์›์ธ์€ ๋น„์‹ผ ๊ณ„์‚ฐ์„ ๊ฑฑ์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.๋ฌธ์„œ์— ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ ์šฉ๋  ๋•Œ ๋ถ€๋ชจ ์„ ํƒ๊ธฐ๋Š” ์‚ฌ์ดํŠธ์˜ ์†๋„์™€ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Chris Coyier cited Jonathan Snook (back in 2010) "๋™์ ์œผ๋กœ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ํŽ˜์ด์ง€์—์„œ ์š”์†Œ๋ฅผ ์‚ญ์ œํ•˜๋ฉด ๋ฌธ์„œ ์ „์ฒด๊ฐ€ ๋‹ค์‹œ ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์ฃผ์š” ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ ๋ฌธ์ œ).
์šฐ๋ฆฌ๊ฐ€ ์ง„์ •์œผ๋กœ ๋ถ€๋ชจ ์„ ํƒ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์„ ๋•Œ, ์•„๋งˆ๋„ ์šฐ๋ฆฌ๋Š” ๊ฐ๋ณ„ํžˆ ์กฐ์‹ฌ์Šค๋Ÿฝ๊ฒŒ ์šฐ๋ฆฌ์˜ ์„ฑ๋Šฅ์„ ํ‰๊ฐ€ํ•ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค.

์„ฑ๋Šฅ ๋ฌธ์ œ ๋ฐฉ์ง€:


์—…๋ฐ์ดํŠธ: ์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.Eric Meyer๋Š” ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ํšŒํ”ผํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ƒ์„ธํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๋Š” nerdy์— ๊ด€ํ•œ ๊ฐ•์—ฐ์„ ์–ธ๊ธ‰ํ–ˆ๋‹ค.
์ดํ›„์— ๋‚˜๋Š” ์œ™ํฌ ์—”์ง„์˜ ์ „๋žต์ด ์–ด๋Š ์ •๋„์— ๊ตญ์ œ ์žฅ๊ธฐ ์—”์ง„์˜ ํšจ์œจ๊ณผ ์œ ์‚ฌํ•˜๋‹ค๊ณ  ๋งํ•˜๊ณ  ์‹ถ๋‹ค. ๊ทธ๊ฒƒ์€ ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ์กฐํ•ฉ ๋™์ž‘์˜ ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ๊ฒฐ๊ณผ๋ฅผ ์˜ˆ์ธกํ•˜์ง€ ์•Š๊ณ  ์ƒ๊ด€์—†๋Š” ๋™์ž‘์„ ์‹ ์†ํ•˜๊ฒŒ ๋ฌด์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„์•ผ ํ•œ๋‹ค.
CSS์˜ ๊ฒฝ์šฐ ๊นœ๋นก์ž„ ์—”์ง„์ด ๊ด€๋ จ๋˜์ง€ ์•Š์€ ์š”์†Œ๋ฅผ ๋ฐ˜๋ณตํ•˜๊ฑฐ๋‚˜ ๋ฌดํšจํ™”ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.์Šคํƒ€์ผ์„ ์ ์šฉํ•œ ํ›„ ์ƒ๊ด€์—†๋Š” ์žฌ๊ณ„์‚ฐ์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ์—”์ง„์€ ์žฌ๊ณ„์‚ฐ ๊ธฐ๊ฐ„์— ์Šคํƒ€์ผ์ด :has() ์ƒํƒœ ๋ณ€๊ฒฝ์˜ ์˜ํ–ฅ์„ ๋ฐ›์•˜๋Š”์ง€ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค.
ํ•˜์ง€๋งŒ ์ด๋ณ‘์šฐ๋Š” ๋ถ€์„ ํƒ๊ธฐ๋ฅผ ์‹คํ˜„ํ•˜๋Š” ๋ฌธ์ œ์™€ ํ•ด๊ฒฐ ๋ฐฉ์•ˆ์˜ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ์„ค๋ช…ํ•ด ๋‹ฌ๋ผ๊ณ  ํ–ˆ๋‹ค.
๊ทธ์˜ ํ•ด์„์—๋Š” ๋ณต์žกํ•œ ์šฉ๋ก€๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด,.a:has(.b ~ .c)ํ˜น์€.a:is(:has(b), :has(c))์ •๋ง!๋‚˜๋Š” ์‹ฌ์ง€์–ด ์ด๊ฒƒ์ด ์œ ํšจํ•œ CSS์ผ์ง€๋„ ๋ชจ๋ฅธ๋‹ค.
์˜์›ํžˆ ๊ณต๋ถ€๋ฅผ ๋ฉˆ์ถ”์ง€ ๋งˆ๋ผ!์ฝ”๋“œ ์‹ฌ์‚ฌ์—์„œ ์ด๋Ÿฐ ์ฝ”๋“œ๋ฅผ ๋ณด์—ฌ์ฃผ์ง€ ๋งˆ์„ธ์š”.์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ณ  ์œ ์ง€ํ•˜๊ธฐ ์‰ฌ์šด ์ธ๊ฐ„ ๋‡Œ๋กœ ์žฌ๊ตฌ์„ฑํ•ด ๋‹ฌ๋ผ๊ณ  ํ• ์ง€๋„ ๋ชฐ๋ผ!

์‹ค์ œ ์šฉ๋ก€


๋ณด์‹œ๋‹ค์‹œํ”ผ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ดhas์„ ํƒ๊ธฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ๋””์ž์ธํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ–‰์šด์˜ ๋‹น์‹ !
๋‹ค์Œ์€ ํ˜„์‹ค ์„ธ๊ณ„์˜ ์˜ˆ์ด๋‹ค. ๋‚˜๋Š” ์ด์ „์— ์ด๋ฏธ ๋ณต์›๋œ Shopware ํ…Œ๋งˆ๋ฅผ ๋ณต์›ํ•ด์•ผ ํ•œ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ์ด๊ฒƒ์€ ๋งค์šฐ ๊ธด๊ธ‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ ์–ด๋„ ๋…ธ์„ ๋„์˜ ์ด ๋ถ€๋ถ„์— ๊นจ๋—ํ•œ ์ฝ”๋“œ๊ฐ€ ์—†๋‹ค.
์—ฌ๊ธฐ!important๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด CMS์—์„œ ์ƒ์„ฑ๋œ ํƒœ๊ทธ์—์„œ ์‹ค์ˆ˜๋กœ ์ž˜๋ชป๋œ ์š”์†Œ๋ฅผ ์ฐพ์„ ์œ„ํ—˜์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.์„ ํƒ๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ๊ธธ์–ด์„œ ์Šคํฌ๋กค์„ ํ•ด์•ผ๋งŒ ๋ชจ๋“  ๋‚ด์šฉ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
/* override template heading style */
body.is-act-index .cms-sections .col-12 .cms-element-alignment.align-self-start {
:has()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ตœ์†Œํ•œ ๋ณต๊ตฌ๊ฐ€ ๋”์šฑ ๋ช…ํ™•ํ•ด์ง‘๋‹ˆ๋‹ค.
/* override template heading style */
body.is-act-index .cms-element-alignment:has(> h1) {
์šฐ๋ฆฌ๋Š” ๋‹จ์ง€ ์ฝ์„ ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค.ํ•˜์ง€๋งŒ ๋ธŒ๋ผ์šฐ์ € ์ง€์›์„ ํ™•๋ณดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Polyfill:has() ์„ ํƒ๊ธฐ๋Š” ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ?


์ตœ๊ทผ CSS ๊ตฌ๋ฌธ์—์„œ ๋ถ€๋ชจ ์„ ํƒ๊ธฐ๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ด๋ฅผ ์ „์†กํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.PostCSS ๋˜๋Š” SASS๋ฅผ ๊ธฐ๋Œ€ํ•˜์ง€ ๋งˆ์„ธ์š”!์ด๋ฒˆ์—๋Š” ๊ธฐ์กด ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ฑ„์šฐ๋ ค๋ฉด JavaScript๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
"๊ธฐ๋ณธ์ ์œผ๋กœ ์˜์›ํžˆ jQuery์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—:has ์„ ํƒ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค"Eric Ponto wrote in 2015 already. jQuery ๊ธฐ๋ฐ˜polyfill:
Polyfill({
    selectors: [":has"]
}).doMatched(rules => {
    rules.each(rule => {
        // just pass it into jQuery since it supports `:has`
        $(rule.getSelectors()).css(rule.getDeclaration())
    });
});

ํ€ด์ฆˆ: ์–ด๋–ป๊ฒŒ jQuery๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์ƒํ™ฉ์—์„œ ๋‹ค๊ฐํ˜•์„ ์ฑ„์›๋‹ˆ๊นŒ?


ํ…Œ์ŠคํŠธ์— ์ฐธ๊ฐ€ํ•˜์—ฌ ํ•ด๊ฒฐ ๋ฐฉ์•ˆ์„ ์ œ์ถœํ•˜์„ธ์š”!
// TODO: add a parent selector polyfill without using jQuery
ํ•ด๊ฒฐ ๋ฐฉ์•ˆ์„ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด StackOverflow question if there is a vanilla JS equivalent of jQuery .has()์˜ ๋‹ต์•ˆ์œผ๋กœ ๋ฐœํ‘œํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

querySelectorAllWithHas


Josh Larson's polyfill-css-has ์ œ๊ณตhas(๋งํฌ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!)
๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ ๋ถ€๋ชจ ์„ ํƒ๊ธฐ๊ฐ€ ์—†๋Š” ์ƒํ™ฉ์—์„œ ์ด๋ ‡๊ฒŒ ์˜ค๋žซ๋™์•ˆ ์‚ด์•˜๋‹ค. ์•„๋งˆ๋„ ์šฐ๋ฆฌ๋Š” ๋” ์ด์ƒ ๊ฑฑ์ •ํ•˜์ง€ ์•Š๊ณ  CSS ์–ธ์–ด์˜ ๋‹ค์Œ ์—…๊ทธ๋ ˆ์ด๋“œ๋ฅผ ๊ณ„์† ์ง„ํ–‰ํ•  ๊ฒƒ์ด๋‹ค.

CSS์˜ ๋‹ค์Œ ๋‹จ๊ณ„๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?


2022๋…„ CSS๋Š” ์–ด๋–ค ์ด์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๊นŒ?
๋˜ํ•œ ๋” ๋งŽ์€ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ด ๊ฐœ๋ฐœ ์ค‘์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ดCSS Container Queries ์šฐ๋ฆฌ๋Š” Chrome๊ณผ Edge์—์„œ ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฐฉ๋ฒ•์€ ๊ธฐ๋Šฅ ํ‘œ์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ทธ๊ฒƒ๋“ค์„ ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
๋ณธ๊ณ ๋Š” 2022๋…„๋ถ€ํ„ฐ ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ๋ฐฐ์šฐ๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒˆ๋กœ์šด CSS ๊ธฐ๋Šฅ์„ ์†Œ๊ฐœํ•˜๋Š” ์ž‘์€ ์‹œ๋ฆฌ์ฆˆ์˜ ์ผ๋ถ€๋ถ„์ด๋‹ค.

์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ