{"id":376342,"date":"2023-01-11T06:18:13","date_gmt":"2023-01-11T14:18:13","guid":{"rendered":"https:\/\/css-tricks.com\/?p=376342"},"modified":"2023-01-11T06:18:16","modified_gmt":"2023-01-11T14:18:16","slug":"has-is-an-unforgiving-selector","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/has-is-an-unforgiving-selector\/","title":{"rendered":":has is an unforgiving selector"},"content":{"rendered":"\n
A little thing happened on the way to publishing the CSS See So, our previous example? The entire selector list is invalid because the bogus selector is invalid. But the other two forgiving selectors, There’s a bit of a workaround for this. Remember, Which one you use might matter because the specificity of :has()<\/code> selector<\/a> to the ol’ Almanac. I had originally described
:has()<\/code> as a “forgiving” selector, the idea being that anything in its argument is evaluated, even if one or more of the items is invalid.<\/p>\n\n\n\n
\/* Example: Do not use! *\/\narticle:has(h2, ul, ::-scoobydoo) { }<\/code><\/pre>\n\n\n\n
::scoobydoo<\/code> in there? That’s totally invalid. A forgiving selector list ignores that bogus selector and proceeds to evaluate the rest of the items as if it were written like this:<\/p>\n\n\n\n
article:has(h2, ul) { }<\/code><\/pre>\n\n\n\n\n\n\n\n
:has()<\/code> was indeed a forgiving selector in a previous draft dated May 7, 2022<\/a>. But that changed after an issue was reported<\/a> that the forgiving nature conflicts with jQuery when
:has()<\/code> contains a complex selector (e.g.
header h2 + p<\/code>). The W3C landed on a resolution to make
:has()<\/code> an “unforgiving” selector<\/a> just a few weeks ago.<\/p>\n\n\n\n
:is()<\/a><\/code> and
:where()<\/a><\/code>, are left unchanged.<\/p>\n\n\n\n
:is()<\/code> and
:where()<\/code>are forgiving, even if
:has()<\/code> is not. That means we can nest either of the those selectors in
:has()<\/code> to get more forgiving behavior:<\/p>\n\n\n\n
article:has(:where(h2, ul, ::-scoobydoo)) { }<\/code><\/pre>\n\n\n\n
:is()<\/code> is determined by the most specific item in its list. So, if you need to something less specific you’d do better reaching for
:where()<\/code> since it does not add to the specificity score.<\/p>\n\n\n\n
\/* Specificity: (0,0,1) *\/\narticle:has(:where(h2, ul, ::-scoobydoo)) { }\n\n\/* Specificity: (0,0,2) *\/\narticle:has(:is(h2, ul, ::-scoobydoo)) { }<\/code><\/pre>\n\n\n\n