CSS :has( ) A Parent Selector Now

I don’t remember the exact moment anymore. But I remember that it was with a mix of disbelief and disappointment that I realized one day that there was no way to select the parent of an element in CSS.

Wait, what? This can’t be. Why?

Obviously, I wasn’t alone. Everyone who has ever learned CSS has probably found themselves in the same situation and asked themselves the same question: Why is it that we don’t have a parent selector in CSS? As Jonathan Snook described in an elaborate post back in 2010, it was not only because of performance concerns but also because of the way browsers render a document and apply the computed styles to elements: as a stream, one element after the other as they come in. When an element is rendered to the viewport, its parent is already there, including all its beautiful styling. Repainting the parent – and, consequently, all other parents – after the fact would then require another evaluation of all parent selectors. This, Remy Sharp agreed back then, would again be so expensive on the render engine that it wouldn't make sense to implement a parent selector.

So, we all accepted the inevitable and did our best to work around it. We added helper classes to our templates via back-end logic or with JavaScript in the frontend. And it somewhat worked. But in almost every project, there still was this one moment where a parent selector would have been the quickest and most “materially honest” solution.

:has has arrived

All of this changed last month when Apple released Safari 15.4 which, as the first browser, supports the :has() pseudo-class, which is one of the CSS Level 4 Selectors. “It was long thought such a selector was not possible, but our team figured out a way to highly optimize performance and deliver a flexible solution that does not slow the page,” Jen Simmons and Jon Davis wrote in the release notes.

There it is. A parent selector. But :has is not only useful as a parent selector. It also opens up a lot more interesting opportunities. But first, let’s have a look at how it works.

The :has pseudo-class takes a relative selector list and will then represent an element if at least one other element matches the selectors in the list. Sounds overly complicated when you write it down, so here is a basic example. Let’s say you want to select all button elements which include an svg element, like an icon. You can now write:

button:has(svg) { … }

Try the CodePen demo – and make sure to view it in Safari 15.4. ;)

Or, if you want to style an article differently if it has a headline inside that is followed by a paragraph:

article:has(h2 + p, h3 + p) { … }

You can also combine :has with the :not pseudo-class to select an element if it does not contain certain other elements, in this case, a headline:

section:not(:has(h1, h2, h3, h4, h5, h6)) { … }

It is also possible to use pseudo-classes like :hover, :focus, or :checked. You could style a form element when a checkbox inside has been checked, for example:

form:has(input[type="checkbox"]:checked) { … }

You could then also use the general sibling combinator ~ to change the styling of the form depending on how many of the checkboxes have been selected:

/* Two checkboxes are :checked… */

form:has(input[type="checkbox"]:checked ~ input[type="checkbox"]:checked) { 
  box-shadow: inset 0 0 0 0.5rem blue;
  background-color: rgb(150, 187, 235);
}

/* Three checkboxes are :checked… */

form:has(input[type="checkbox"]:checked ~ input[type="checkbox"]:checked ~ input[type="checkbox"]:checked) { 
  box-shadow: inset 0 0 0 0.5rem rgb(0, 160, 0);
  background-color: rgb(136, 233, 136);
}

Try the CodePen demo.

Although this demo might not be the most practical example, all this is still starting to get interesting, right?

Using :has to adjust a Grid

CSS Grid generally works from the container in and before :has, there wasn’t really a way to adjust the Grid based on what’s inside. What if we could use :has to adjust the CSS Grid layout of a container based on the number of elements inside of it? Here, so-called quantity queries can be useful. Heydon Pickering has written the ultimate article about them. By combining the :nth-child and :nth-last-child pseudo-classes inside our :has selector list, we can adjust the layout by “counting” the elements inside. Here is how we can target a grid with two elements inside, for example:

.grid:has(:nth-child(2):last-child) {
  grid-template-columns: 1fr 1fr;
}

So, if our Grid container has an element inside that is both the second child as well as the last child of our container, the grid should have two columns. The same also works with three columns:

.grid:has(:nth-child(3):last-child) {
  grid-template-columns: 1fr 1fr 1fr;
}

Finally, we can also create a grid layout that has four columns if the container has four or more elements inside. To achieve this, we select at least one element that is either the fourth or one of all following elements:

.grid:has(:nth-child(n+4)) {
  grid-template-columns: repeat(4, 1fr);
}

Here is a CodePen demo again.

As you can see, there are lots of amazing use cases for :has as a parent selector and it still feels like this is only scratching the surface of what people will come up with. :has lets us style elements based on whether the child of an element is selected, has focus, or whether it is present at all. And we can even target an element based on how many children it has. All this will allow for much more flexible components. Just think of all the variations of content and context that can exist inside a design system and you know how valuable this will be.

But wait, there is more!

:has as a previous sibling selector

Because :has accepts a relative selector list, you can also select an element if it has another element that follows it. Or, in other words, we can use :has to select the previous sibling of an element:

:has(+ .second) {
  background-color: darkmagenta;
}

Try it on CodePen.

Again, there are so many practical use cases for this! For example, you could style an image differently when there is a caption below it:

figure img:has(+ figcaption) {
  /* Do something with the image */
}

The possibilities of using :has in useful and creative ways to write more flexible and robust CSS seem endless. And as is the case with so many of the new features that are currently being added to CSS, I can't wait to see what other creative uses for :has you all come up with. One recent example is this brilliant demo by Michelle Barker, where she combines animated grid tracks with the :has selector.

Testing for support

For now, Safari is the only browser with support for :has. In the upcoming version 101 of Chrome, you’ll be able to activate it via the Experimental Web Platform features flag, however. While this is promising, it will certainly take a little while until :has is supported by the majority of browsers. In the meantime, we can once more use progressive enhancement to already use :has in browsers that support it. As Michelle Barker notes, you can test for support for :has with a @supports feature query using the selector() function:

@supports selector(:has(*)) {
  /* Code for browsers with support for :has */
}

Thus, you can target supporting browsers in a future friendly way. Because once :has is supported by another browser, your code will work automatically in this browser as well.

Do you have more ideas about how to use :has? Have you seen more interesting examples and demos? And will you start using it already? Let me know via Webmention, email, or Twitter.

Links

~

681 Webmentions

Photo of Soily Sound
Soily Sound
`grid-auto-flow: column` is probably a better way of achieving that last one…
Photo of Stefan Judis
Stefan Judis
Oh my... 🙈; That's a brain teaser! :D Thanks Matthias! 🙇;‍♂;️;
Photo of Save to Notion
Save to Notion
This Thread is Saved to your Notion Workspace. These tags were saved to the thread [Css, Selector, Has]
Photo of Pablo Lara H
Pablo Lara H
⚫;️; CSS :has( ) A Parent Selector Now by Matthias Ott @m_ott #has #css #Layout #PseudoClasses #Selectors #webdev matthiasott.com/notes/css-has-…
Photo of Rodrigo Pedra Brum
Rodrigo Pedra Brum
For those on linux, GNOME Web (Epiphany), which uses WebKit under the hood, already has support for this new selector ;) Useful for seeing the demos and testing new code.
Photo of Rami
Rami
I think it,s just at safari
Photo of Elise
Elise
Safari apparently supports the :has() CSS selector, which opens up some interesting possibilities, aka real psychopath shit that I am sincerely excited about.
Photo of Stefan Judis
Stefan Judis
There's good content like this brain-teasing selector in @m_ott article on CSS :has(). 👇;👏; matthiasott.com/notes/css-has-…
Photo of Matthias Ott ????;????;
Matthias Ott ????;????;
Safari is the first browser to support it, yes. It will also be beging a flag in Chrome in the next version. And if you want to use it, you could check for support with a feature query like @​;supports selector(:has(*))
Photo of ogi
ogi
こ;れ;「;ド;エ;レ;ー; ;"cool" ;じ;ゃ;ん;・;・;・;・;?;」;た;だ;tailwindの;台;頭;で;CSS層;よ;り;も;HTMLを;太;ら;せ;る;の;が;metaと;い;う;感;じ;も;す;る;の;で;10年;早;く;欲;し;か;っ;た;ッ;ピ;(;無;茶;);
Photo of С;т;. 122 У;К; Р;Б;
С;т;. 122 У;К; Р;Б;
Е;щ;е; о;д;н;а; х;о;р;о;ш;а;я; п;о;д;б;о;р;к;а; п;о;л;е;з;н;ы;х; п;р;и;м;е;н;е;н;и;й; с;е;л;е;к;т;о;р;а; :has(), в;п;р;и;д;а;ч;у; к; css-live.ru/css/psevdoklas… :)
Photo of Ben Schwarz
Ben Schwarz
Real talk: selectors as complex as this require through documentation and are a total liability for a production codebase
Photo of Ben Schwarz
Ben Schwarz
And also, cool! Fun use of adjacent sibling, :checked & :has
Photo of Stefan Judis
Stefan Judis
Such selector needs docs for sure. I'm just super fascinated by all the use cases it enables. 😲; In a few years we'll look back saying "Remember when we haven't had the :has() selector? That was tough!".
Photo of Ben Schwarz
Ben Schwarz
I remember the days of float layout and in retrospect tables were better 🥹;
Photo of EJCSoftwareSolutions
EJCSoftwareSolutions
Top story: CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…, see more tweetedtimes.com/helikopterdsgn…
Photo of Focus Mobility
Focus Mobility
Top story: CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…, see more tweetedtimes.com/helikopterdsgn…
Photo of Rafał; Grabie
Rafał; Grabie
Top story: CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…, see more tweetedtimes.com/v/21215?s=tnp
Photo of Chris ????; Browsers
Chris ????; Browsers
You need to put a selector before :has though. That means you need to know something about the parent. I guess you could do "*:has(> .my-class)" but that feels a bit horrible...
Photo of Dennis Frank
Dennis Frank
CAN I HAS :HAS? Another use case I just prototyped: Style select based on option value codepen.io/df/pen/zYpaVWM
Photo of Hari Madhav
Hari Madhav
Very insightful and educative. Thanks for the article
Photo of George aka Gplus Web
George aka Gplus Web
Thank you for the write-up, but I'd like to point out : most of these examples seem very inefficient selectors. What's the problem with adapting your HTML to suit your styling needs? Definitely more performant
Photo of Chris ????; Browsers
Chris ????; Browsers
I don't think "set these styles on this element if it contains these children" is the same as a parent selector. A parent selector would be "set these styles on the parent of this element". The important bit is that a parent selector doesn't need to know the HTML structure.
Photo of Matthias Ott ????;????;
Matthias Ott ????;????;
I’d argue that there are other, much more efficient ways to improve performance (👀;, JavaScript) than to optimize for selector performance. The differences are negligible, even * is not a problem anymore – although it would be interesting to see if this is different for :has… 🤔;
Photo of Matthias Ott ????;????;
Matthias Ott ????;????;
🤔; In “set these styles on the parent of this element”, “this element” needs to be selected via CSS, correct? E.g. ".my-class". If you then use :has(> .my-class) { … } you’re selecting the parent of this element without the need to know the HTML structure.
Photo of Digital Art Creative
Digital Art Creative
Top story: CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…, see more tweetedtimes.com/helikopterdsgn…
Photo of Dennis Frank
Dennis Frank
Yeah! It's so easy now to add a bit of custom theming. Speaking of theming: Simple theme switch with :has() codepen.io/df/pen/MWrBWbO
Photo of Mylo
Mylo
using pseudo classes or pseudo elements without * before them acts as if it were there anyway
Photo of Ange Picard
Ange Picard
Imagine `:has` coupled to container queries. 🤯;
Photo of Matthias Ott ????;????;
Matthias Ott ????;????;
Oh, yes! You could try it in Safari TP and write about it / create a CodePen demo. 😉;😉;😉; webkit.org/blog/12563/rel…
Photo of Mylo
Mylo
apparently chrome has added it now, but i wouldn't immediately start using it everywhere. edge and firefox are widely used still
Photo of Matthias Ott ????;????;
Matthias Ott ????;????;
Yes, sure! I also mention this in the article. You could use a feature query to check for support if it makes sense to use it in a project already.
Photo of pixelgeek
pixelgeek
Can I has this in all browsers soon pls? matthiasott.com/notes/css-has-…
Photo of ng-gunma
ng-gunma
CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
Photo of D7460N
D7460N
I really liked this, check it out : ✨;✍;️; New post: CSS :has( ) A Parent Selector Now matthiasott.com/notes/css-has-… — Matthias Ott 🇺;🇦; (@m_ott) Apr 10, 2022
Photo of Joel Berger
Joel Berger
Browsers may not have had the #css4 selector ":has" until now, but @mojolicious_org has had it for years! docs.mojolicious.org/Mojo/DOM/CSS#E…
Photo of Jakub T. Jankiewicz
Jakub T. Jankiewicz
Hej @Comandeer2 obczaj swój komentarz na moim blogu z 2018. jcubic.pl/2018/04/selekt…
Photo of Šime (she-meh) ????;
Šime (she-meh) ????;
I thought form:has(:nth-child(3 of :checked)) would work in Safari, but it doesn’t for some reason.
Photo of Mylo
Mylo
it is, but it probably has a seperate entry on compatibility for a reason
Photo of Must Creative
Must Creative
CSS :has( ) A Parent Selector Now matthiasott.com/notes/css-has-…
Photo of Pawel Grzybek
Pawel Grzybek
"CSS :has( ) A Parent Selector Now" by @m_ott is so good. Bunch of practical examples of :has() pseudo-class + tons of CodePens. matthiasott.com/notes/css-has-… #css
Photo of Siavash
Siavash
CSS :has( ) A Parent Selector Now #CSS matthiasott.com/notes/css-has-…
Photo of Sigma:Funk
Sigma:Funk
CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of Alex Hall
Alex Hall
CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of Quentin Bellanger
Quentin Bellanger
":has()" parent selector will unlock so many possibilities and reduce the amount of code! #css matthiasott.com/notes/css-has-…
Photo of Fatih Hayrioğ;lu
Fatih Hayrioğ;lu
CSS Parent seçicisini(:has) örnekler anlatan güzel bir makale. Parent uzun süredir beklediğ;imiz bir yetenekti. Gelince biraz duraksadı;k ama örnekleri gördükçe heyecanlanı;yorum.🎉; CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
Photo of Ferdinand Vogler
Ferdinand Vogler
This is great. So everytime I’m using a modifier class such as .button—has-icon I can now use .button:has(.icon). Reduces some code 🙂; Thanks for the article.
Photo of Save to Notion
Save to Notion
Saved to your Notion Workspace. These tags where saved to the tweet [Css]
Photo of dirk döring
dirk döring
article:has(.value) by @m_ott matthiasott.com/notes/css-has-… CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of Antonio ☻;
Antonio ☻;
CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of Pinboard Popular
Pinboard Popular
CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
Photo of Tom
Tom
CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of Jacky
Jacky
CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
Photo of Joseph Klem
Joseph Klem
Good news for front-end designers and devs — by @m_ott matthiasott.com/notes/css-has-…
Photo of nuncapops
nuncapops
CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
Photo of Kat Fay
Kat Fay
Here's a really helpful explanation of new the :has() #CSS selector by @m_ott 🙏;🏻; Explained so that #CodeNewbies like me 🌱; can understand, it also goes into detail for the #webdesign experts out there 🧙;🏻;‍♂;️; ⌨;️; CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of D7460N
D7460N
matthiasott.com/notes/css-has-…
Photo of Lazy McGrady
Lazy McGrady
nah this is dope CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of MJCoder
MJCoder
#CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-… by @m_ott
Photo of Tammy Jensen
Tammy Jensen
CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of Yohan J. Rodríguez
Yohan J. Rodríguez
#CSS #Automated | CSS :has() A Parent Selector Now matthiasott.com/notes/css-has-…
Photo of Sergey Romanenko
Sergey Romanenko
Matthias Ott explains how the :has() selector works and shows how it's not only useful as a parent selector. matthiasott.com/notes/css-has-… #css
Photo of Marco Von Ballmoos
Marco Von Ballmoos
CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-… via @instapaper
Photo of Ashraf Hamdy
Ashraf Hamdy
This is quite interesting! CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of Friday Front-End
Friday Front-End
CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of Joulse
Joulse
CSS :has( ) A Parent Selector Now matthiasott.com/notes/css-has-…
Photo of Ann
Ann
CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of Lukas Borawski
Lukas Borawski
Finally, :has has arrived 😃; #css #web #dev #programming matthiasott.com/notes/css-has-…
Photo of Michael Bladowski
Michael Bladowski
#CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
Photo of Garry Kane
Garry Kane
CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of Dave
Dave
CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
Photo of Robert DeVore
Robert DeVore
CSS :has() A Parent Selector Now matthiasott.com/notes/css-has-… via @m_ott
Photo of thorsten
thorsten
But Browser Support is quite bad in the moment caniuse.com/css-has
Photo of Matthias Ott
Matthias Ott
Yes, that’s true, I would not use it for anything super critical at the moment. But it’s on the horizon (also in Chrome), so I already started adding it here and there for little (progressive) enhancements. 🤫;😜;
Photo of Neil
Neil
matthiasott.com/notes/css-has-…
Photo of Helen
Helen
i:not(:has(time)) but still excited for when this pseudo-selector gets more support! A helpful/hype article about this matthiasott.com/notes/css-has-… @m_ott via @CodePen
Photo of Matthias Ott
Matthias Ott
Also added it to the list of resources at the bottom of my :has() article from earlier this year: matthiasott.com/notes/css-has-…
Photo of İ;lker Kurtel
İ;lker Kurtel
1- webkit.org/blog/13096/css… 2- css-irl.info/animated-grid-… 3- matthiasott.com/notes/css-has-… 4- daverupert.com/2022/07/solvin… 5- css-tricks.com/the-css-has-se… 6- blog.logrocket.com/advanced-guide… 7- developer.chrome.com/blog/has-m105/ 8- bram.us/2021/12/21/the…

Likes

Reposts