CSS :has( ) A Par­ent Selec­tor 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.

~

690 Webmentions

  1. CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
  2. 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…
  3. Also added it to the list of resources at the bottom of my :has() article from earlier this year: matthiasott.com/notes/css-has-…
  4. 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
  5. Every day the CSS world has presented steady improments. Have a look at the article bellow: matthiasott.com/notes/css-has-…
  6. matthiasott.com/notes/css-has-…
  7. 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. 🤫😜
  8. But Browser Support is quite bad in the moment caniuse.com/css-has
  9. CSS :has() A Parent Selector Now matthiasott.com/notes/css-has-… via @m_ott
  10. CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
  11. CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
  12. #CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
  13. Finally, :has has arrived 😃 #css #web #dev #programming matthiasott.com/notes/css-has-…
  14. CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
  15. CSS :has( ) A Parent Selector Now matthiasott.com/notes/css-has-…
  16. CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
  17. This is quite interesting! CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
  18. CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-… via @instapaper
  19. 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
  20. CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
  21. #CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-… by @m_ott
  22. nah this is dope CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
  23. 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-…
  24. 📝 CSS :has( ) A Parent Selector Now 🔗 matthiasott.com/notes/css-has-… #html #css #javascript #webdev
  25. We were promised flying cars, and we got something very close. :has( ) has arrived. matthiasott.com/notes/css-has-…
  26. CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
  27. CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
  28. Good news for front-end designers and devs — by @m_ott matthiasott.com/notes/css-has-…
  29. CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
  30. matthiasott.com/notes/css-has-… #frontenddevelopment #twitter #CSS #softwaredevelopment #stylingtips #frontenddeveloper #softwareengineering #css
  31. CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
  32. CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
  33. CSS 开;始;支;持;父;选;择;器;了; 我;们;一;直;都;被;教;育;:;CSS 不;能;直;接;定;义;父;级;元;素;,;这;么;定;义;等;于;把;渲;染;完;的;元;素;重;新;渲;染;,;会;慢;死; 结;果;苹;果; Safari 开;始;支;持; :has() 伪;类;,;能;不;降;低;页;面;速;度;地;实;现;父;选;择;器;,;据;说;他;们;找;到;了;高;度;优;化;性;能;的;方;法; 这;位;设;...
  34. CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
  35. 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-…
  36. Saved to your Notion Workspace. These tags where saved to the tweet [Css]
  37. 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.
  38. 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-…
  39. ":has()" parent selector will unlock so many possibilities and reduce the amount of code! #css matthiasott.com/notes/css-has-…
  40. CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
  41. CSS :has( ) A Parent Selector Now, by @m_ott matthiasott.com/notes/css-has-…
  42. CSS :has( ) A Parent Selector Now #CSS matthiasott.com/notes/css-has-…
  43. "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
  44. CSS :has( ) A Parent Selector Now matthiasott.com/notes/css-has-…
  45. it is, but it probably has a seperate entry on compatibility for a reason
  46. I thought form:has(:nth-child(3 of :checked)) would work in Safari, but it doesn’t for some reason.
  47. Hej @Comandeer2 obczaj swój komentarz na moim blogu z 2018. jcubic.pl/2018/04/selekt…
  48. 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…
  49. 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
  50. CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…
  51. Can I has this in all browsers soon pls? matthiasott.com/notes/css-has-…
  52. 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.
  53. apparently chrome has added it now, but i wouldn't immediately start using it everywhere. edge and firefox are widely used still
  54. Oh, yes! You could try it in Safari TP and write about it / create a CodePen demo. 😉😉😉 webkit.org/blog/12563/rel…
  55. using pseudo classes or pseudo elements without * before them acts as if it were there anyway
  56. 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
  57. Top story: CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…, see more tweetedtimes.com/helikopterdsgn…
  58. 🤔 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.
  59. 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… 🤔
  60. 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.
  61. 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
  62. CAN I HAS :HAS? Another use case I just prototyped: Style select based on option value codepen.io/df/pen/zYpaVWM
  63. 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...
  64. 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
  65. Top story: CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…, see more tweetedtimes.com/helikopterdsgn…
  66. Top story: CSS :has( ) A Parent Selector Now · Matthias Ott – User Experience Designer matthiasott.com/notes/css-has-…, see more tweetedtimes.com/helikopterdsgn…
  67. I remember the days of float layout and in retrospect tables were better 🥹
  68. 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!".
  69. And also, cool! Fun use of adjacent sibling, :checked & :has
  70. Real talk: selectors as complex as this require through documentation and are a total liability for a production codebase
  71. Е;щ;е; о;д;н;а; х;о;р;о;ш;а;я; п;о;д;б;о;р;к;а; п;о;л;е;з;н;ы;х; п;р;и;м;е;н;е;н;и;й; с;е;л;е;к;т;о;р;а; :has(), в;п;р;и;д;а;ч;у; к; css-live.ru/css/psevdoklas… :)
  72. こ;れ;「;ド;エ;レ;ー; ;"cool" ;じ;ゃ;ん;・;・;・;・;?;」;た;だ;tailwindの;台;頭;で;CSS層;よ;り;も;HTMLを;太;ら;せ;る;の;が;metaと;い;う;感;じ;も;す;る;の;で;10年;早;く;欲;し;か;っ;た;ッ;ピ;(;無;茶;);
  73. 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(*))
  74. There's good content like this brain-teasing selector in @m_ott article on CSS :has(). 👇👏 matthiasott.com/notes/css-has-…
  75. Safari apparently supports the :has() CSS selector, which opens up some interesting possibilities, aka real psychopath shit that I am sincerely excited about.
  76. 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.
  77. ⚫;️; CSS :has( ) A Parent Selector Now by Matthias Ott @m_ott #has #css #Layout #PseudoClasses #Selectors #webdev matthiasott.com/notes/css-has-…
  78. This Thread is Saved to your Notion Workspace. These tags were saved to the thread [Css, Selector, Has]
  79. Oh my... 🙈 That's a brain teaser! :D Thanks Matthias! 🙇‍♂;️;
  80. `grid-auto-flow: column` is probably a better way of achieving that last one…

45 Reposts

ⓘ Webmentions are a way to notify other websites when you link to them, and to receive notifications when others link to you. Learn more about Webmentions.