A place to cache linked articles (think custom and personal wayback machine)
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

8 месяцев назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. title: CSS :has() Interactive Guide
  2. url: https://ishadeed.com/article/css-has-guide/
  3. hash_url: 02eaae467a3a88479393c9fe026f655a
  4. archive_date: 2024-03-07
  5. og_image: https://ishadeed.com/assets/css-has-guide/twitter-card.jpg
  6. description: Everything you need to know about CSS :has() selector.
  7. favicon: https://ishadeed.com/assets/favicon-32x32.png
  8. language: en_US
  9. <div class="post-content prose"> <h2 id="intro">Intro</h2>
  10. <p>We always wanted a way in CSS to style an element based on its descendants. It wasn’t possible until CSS <code>:has()</code> became supported in all major browsers.</p>
  11. <p>In this article, I will explore the problem and shed the light on some of the interesting use cases for CSS <code>:has()</code>.</p>
  12. <h3 id="the-problem">The problem</h3>
  13. <p>Say we have a <code>&lt;figure&gt;</code> and we want to style it differently if it has a <code>&lt;figcaption&gt;</code>. How to achieve that in CSS?</p>
  14. <pre class="language-html"><code is:raw="" class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figure</span><span class="token punctuation">&gt;</span></span>
  15. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>thumb.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
  16. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>figcaption</span><span class="token punctuation">&gt;</span></span>A great looking tart.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figcaption</span><span class="token punctuation">&gt;</span></span>
  17. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>figure</span><span class="token punctuation">&gt;</span></span></code></pre>
  18. <p>See the following demo. Try to toggle the “Show caption”.</p>
  19. <astro-island uid="xNGJK" prefix="r1" component-url="/_astro/FigCaption.DS0PjoJ7.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"1"]}' ssr="" client="visible" opts='{"name":"FigCaption","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_6w5nk_1"><div class="_sampleProse_6w5nk_10"><p>See the following figure:</p><figure class="_figure_6w5nk_21"><img src="/assets/css-has-guide/tart.jpeg" alt=""><figcaption>A great looking tart.</figcaption></figure></div></div></div></astro-island>
  20. <p>When there is a caption, I want the figure to have the following:</p>
  21. <ul>
  22. <li>Padding</li>
  23. <li>Background</li>
  24. <li>Shadow</li>
  25. </ul>
  26. <p>The only possible way in CSS is to give a class to the <code>&lt;figure&gt;</code>, and then select the <code>&lt;figcaption&gt;</code> from that class.</p>
  27. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">figure.with-caption</span> <span class="token punctuation">{</span>
  28. <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  29. <span class="token property">background-color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  30. <span class="token property">box-shadow</span><span class="token punctuation">:</span> 0 3px 10px 0 <span class="token function">rgba</span><span class="token punctuation">(</span>0<span class="token punctuation">,</span> 0<span class="token punctuation">,</span> 0<span class="token punctuation">,</span> 0.1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  31. <span class="token property">border-radius</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
  32. <span class="token punctuation">}</span></code></pre>
  33. <p>This is not doable when we have generated HTML content (e.g: an article body).</p>
  34. <h3 id="the-solution">The solution</h3>
  35. <p>With the CSS <code>:has()</code> selector, this is possible. We can do the following. It’s like saying if the <code>&lt;figure&gt;</code> contains a <code>&lt;figcaption&gt;</code>, style it that way.</p>
  36. <p>Can you guess the solution? Try to type it below and see the result in action. As a reminder, you need to type <code>:has</code> and the selector you want.</p>
  37. <astro-island uid="Z2pLpWi" prefix="r2" component-url="/_astro/TestEdit.CN3ZTb5O.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"showCode":[0,true]}' ssr="" client="visible" opts='{"name":"TestEdit","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_10e1k_1"><p>Write the CSS selector needed to style the <strong>figure</strong> only if it has a <strong>figcaption</strong>.</p><div><div class="_demoInputWrapper_10e1k_18"><div><p><strong>.figure</strong><input class="_demoInput_10e1k_18" type="text" spellcheck="false">{</p><p>padding: 0.5rem; <br>background-color: #fff; <br>border-radius: 8px;</p><p>}</p></div></div><figure class="_figure_10e1k_61 false"><img src="/assets/css-has-guide/tart.jpeg" alt=""><figcaption>A great looking tart.</figcaption></figure></div><div class="_code_10e1k_96"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">figure</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">img</span><span class="token tag"> </span><span class="token tag attr-name">src</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">thumb.jpg</span><span class="token tag attr-value punctuation">"</span><span class="token tag"> </span><span class="token tag attr-name">alt</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value punctuation">"</span><span class="token tag"> </span><span class="token tag punctuation">/&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">figcaption</span><span class="token tag punctuation">&gt;</span><span class="token plain">A great looking tart.</span><span class="token tag punctuation">&lt;/</span><span class="token tag">figcaption</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">figure</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  38. <details><summary><p>Reveal the solution <span aria-hidden="true">👀</span></p></summary><pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">figure:has(figcaption)</span> <span class="token punctuation">{</span>
  39. <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  40. <span class="token property">background-color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  41. <span class="token property">box-shadow</span><span class="token punctuation">:</span> 0 3px 10px 0 <span class="token function">rgba</span><span class="token punctuation">(</span>0<span class="token punctuation">,</span> 0<span class="token punctuation">,</span> 0<span class="token punctuation">,</span> 0.1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  42. <span class="token property">border-radius</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
  43. <span class="token punctuation">}</span></code></pre></details>
  44. <p>In the following demo, notice how when the <code>&lt;figcaption&gt;</code> is commented, the CSS <code>:has()</code> takes action.</p>
  45. <astro-island uid="ZSbBRV" prefix="r3" component-url="/_astro/FigCaption.DS0PjoJ7.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"1"],"showCode":[0,true]}' ssr="" client="visible" opts='{"name":"FigCaption","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_6w5nk_1"><div class="_sampleProse_6w5nk_10"><p>See the following figure:</p><figure class="_figure_6w5nk_21"><img src="/assets/css-has-guide/tart.jpeg" alt=""><figcaption>A great looking tart.</figcaption></figure></div><div class="_code_6w5nk_66"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">figure</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">img</span><span class="token tag"> </span><span class="token tag attr-name">src</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">thumb.jpg</span><span class="token tag attr-value punctuation">"</span><span class="token tag"> </span><span class="token tag attr-name">alt</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value punctuation">"</span><span class="token tag"> </span><span class="token tag punctuation">/&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">figcaption</span><span class="token tag punctuation">&gt;</span><span class="token plain">A great looking tart.</span><span class="token tag punctuation">&lt;/</span><span class="token tag">figcaption</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">figure</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  46. <p>This is just scratching the surface of problems we can solve with CSS <code>:has()</code>.</p>
  47. <h2 id="css-selectors-recap">CSS selectors recap</h2>
  48. <p>Before diving into some interesting CSS selectors with <code>:has()</code>, let’s do a quick recap on them.</p>
  49. <h3 id="adjacent-sibling-selector">Adjacent sibling selector</h3>
  50. <p>To select the next sibling of an element, we can use the adjacent sibling selector (+) for that.</p>
  51. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.book</span> <span class="token punctuation">{</span>
  52. <span class="token property">opacity</span><span class="token punctuation">:</span> 0.2<span class="token punctuation">;</span>
  53. <span class="token punctuation">}</span>
  54. <span class="token selector">.frame + .book</span> <span class="token punctuation">{</span>
  55. <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
  56. <span class="token punctuation">}</span></code></pre>
  57. <p>Try it yourself in the demo below.</p>
  58. <astro-island uid="ZkPcpy" prefix="r4" component-url="/_astro/SelectorsRecap.3Oha4ybT.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"adjacent"]}' ssr="" client="visible" opts='{"name":"SelectorsRecap$2","value":true}' await-children=""><div class="example-wrapper center _wrapper_s0lex_1"><p>Select the book that is next to the frame</p></div></astro-island>
  59. <h3 id="general-sibling-selector">General sibling selector</h3>
  60. <p>To select all the next siblings of an element, we can use the general sibling selector (~) for that.</p>
  61. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.book</span> <span class="token punctuation">{</span>
  62. <span class="token property">opacity</span><span class="token punctuation">:</span> 0.2<span class="token punctuation">;</span>
  63. <span class="token punctuation">}</span>
  64. <span class="token selector">.frame ~ .book</span> <span class="token punctuation">{</span>
  65. <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
  66. <span class="token punctuation">}</span></code></pre>
  67. <astro-island uid="Z1qa8kO" prefix="r5" component-url="/_astro/SelectorsRecap.3Oha4ybT.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"general"]}' ssr="" client="visible" opts='{"name":"SelectorsRecap$2","value":true}' await-children=""><div class="example-wrapper center _wrapper_s0lex_1"><p>Select <strong>all the books</strong> that are after the frame</p></div></astro-island>
  68. <h3 id="the-previous-sibling-selector">The previous sibling selector</h3>
  69. <p>With CSS <code>:has()</code>, we can take the above further and select the previous sibling of an element.</p>
  70. <p>In the following snippet, the <code>:has()</code> makes it possible to select a book that is followed by a frame.</p>
  71. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.book</span> <span class="token punctuation">{</span>
  72. <span class="token property">opacity</span><span class="token punctuation">:</span> 0.2<span class="token punctuation">;</span>
  73. <span class="token punctuation">}</span>
  74. <span class="token selector">.book:has(+ .frame)</span> <span class="token punctuation">{</span>
  75. <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
  76. <span class="token punctuation">}</span></code></pre>
  77. <astro-island uid="Zm5byI" prefix="r6" component-url="/_astro/SelectorsRecap.3Oha4ybT.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"previous"]}' ssr="" client="visible" opts='{"name":"SelectorsRecap$2","value":true}' await-children=""><div class="example-wrapper center _wrapper_s0lex_1"><p>Select <strong>the previous element</strong> before the frame.</p></div></astro-island>
  78. <p>Adding on the above, we can select all of the <strong>previous elements</strong> of a specific element. In our case, we want to select all the <code>.book</code>s before the <code>.frame</code> element.</p>
  79. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.book</span> <span class="token punctuation">{</span>
  80. <span class="token property">opacity</span><span class="token punctuation">:</span> 0.2<span class="token punctuation">;</span>
  81. <span class="token punctuation">}</span>
  82. <span class="token selector">.book:has(~ .frame)</span> <span class="token punctuation">{</span>
  83. <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
  84. <span class="token punctuation">}</span></code></pre>
  85. <astro-island uid="26qPnJ" prefix="r7" component-url="/_astro/SelectorsRecap.3Oha4ybT.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"previousGeneral"]}' ssr="" client="visible" opts='{"name":"SelectorsRecap$2","value":true}' await-children=""><div class="example-wrapper center _wrapper_s0lex_1"><p>Select all the <code>.book</code> elements before the <code>.frame</code>.</p></div></astro-island>
  86. <h3 id="the-child-combinator">The child combinator</h3>
  87. <p>The <code>&gt;</code> selector selects an element if it’s the direct child only. For example, using <code>.section &gt; h1</code> will select an <code>&lt;h1&gt;</code> only if it’s a direct child of the section.</p>
  88. <p>Review your knowledge with the demo below.</p>
  89. <astro-island uid="ZjDfu7" prefix="r8" component-url="/_astro/SelectorsDirect.CE2P0PNM.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"SelectorsRecap","value":true}' await-children=""><div class="example-wrapper center _wrapper_1ntyn_1"><p>Select the <code>.book</code> that are inside the <code>.box</code></p></div></astro-island>
  90. <h3 id="the-not-pseudo-class">The :not pseudo-class</h3>
  91. <p>The <code>:not()</code> selector in CSS is useful to exclude an element from a selection. For example, <code>.section:not(.featured)</code>. Try the demo below and select all books except the <code>.blue</code> one.</p>
  92. <astro-island uid="136n0v" prefix="r9" component-url="/_astro/SelectorsNot.O2ZEYcyg.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"SelectorsRecap$1","value":true}' await-children=""><div class="example-wrapper center _wrapper_12u5c_1"><p>Select all books except the <code>.blue</code></p></div></astro-island>
  93. <p>That’s it for the selectors recap. It was important to set clear expectations and make sure that any upcoming example that explains them is clear to you.</p>
  94. <h2 id="css-has-selectors-matching">CSS :has() selectors matching</h2>
  95. <p>Learning to read a CSS <code>:has()</code> selector is useful. In this section, I will go through a few examples and show you how to analyze them.</p>
  96. <p>The following are general examples for you to practise.</p>
  97. <h3 id="card-with-image">Card with image</h3>
  98. <p>In this example, we have a card with an image as a child element. We can check that with CSS <code>:has()</code>.</p>
  99. <p>Try to toggle the checkbox and see how the CSS selector works only when there is an image.</p>
  100. <astro-island uid="D7IG" prefix="r10" component-url="/_astro/Card.Bh0yW6fM.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"card-img"]}' ssr="" client="visible" opts='{"name":"CardAnalyse","value":true}' await-children=""><div class="example-wrapper center _wrapper_100uz_1"><div class="_innerContent_100uz_13"><div><p class="_explain_100uz_20">select all <strong>.card</strong> that contain an <strong>img</strong></p><p class="_arrow_100uz_32"></p></div><div><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">card</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">card-content</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  101. <p>What if we want a selector that should match only <strong>if the image is a direct child</strong> of the card? When the <code>.card-thumb</code> element is there, it won’t match.</p>
  102. <p>Try it yourself.</p>
  103. <astro-island uid="ZAqYGx" prefix="r11" component-url="/_astro/Card.Bh0yW6fM.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"card-direct-img"]}' ssr="" client="visible" opts='{"name":"CardAnalyse","value":true}' await-children=""><div class="example-wrapper center _wrapper_100uz_1"><div class="_innerContent_100uz_13"><div><p class="_explain_100uz_20">select all <strong>.card</strong> that contain a direct<strong> img</strong> child</p><p class="_arrow_100uz_32"></p></div><div><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">card</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">card-thumb</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">img</span><span class="token tag"> </span><span class="token tag attr-name">src</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">thumb.jpg</span><span class="token tag attr-value punctuation">"</span><span class="token tag"> </span><span class="token tag attr-name">alt</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value punctuation">"</span><span class="token tag"> </span><span class="token tag punctuation">/&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">card-content</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  104. <h3 id="card-without-an-image">Card without an image</h3>
  105. <p>CSS <code>:has()</code> can be combined with the <code>:not()</code> selector. In this case, the card selector will match <strong>only if it doesn’t have an image</strong>.</p>
  106. <astro-island uid="MMWh9" prefix="r12" component-url="/_astro/Card.Bh0yW6fM.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"no-img"]}' ssr="" client="visible" opts='{"name":"CardAnalyse","value":true}' await-children=""><div class="example-wrapper center _wrapper_100uz_1"><div class="_innerContent_100uz_13"><div><p class="_explain_100uz_20">select all <strong>.card</strong> that <strong>doesn't</strong> contain an <strong>img</strong></p><p class="_arrow_100uz_32"></p></div><div><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">card</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">img</span><span class="token tag"> </span><span class="token tag attr-name">src</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">thumb.jpg</span><span class="token tag attr-value punctuation">"</span><span class="token tag"> </span><span class="token tag attr-name">alt</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value punctuation">"</span><span class="token tag"> </span><span class="token tag punctuation">/&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">card-content</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  107. <h3 id="adjacent-sibling-and-has">Adjacent sibling and :has</h3>
  108. <p>See the following demo. We want to select the <code>.shelf</code> that contains the frame that is followed by a purple book.</p>
  109. <p>By default, the frame comes after the book. Toggle the checkbox and see how the CSS <code>:has()</code> selector will work.</p>
  110. <astro-island uid="2sWq5h" prefix="r13" component-url="/_astro/ElementFollowedBy2.DOsNK8yE.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"ElementFollowedBy2$4","value":true}' await-children=""><div class="example-wrapper center _wrapper_6sh2w_1"><p class="_checkbox_4pedb_1 _mainColor_4pedb_4"><input id=":r13R1:" type="checkbox" class="_srOnly_4pedb_43 _input_4pedb_8"><label class="_label_4pedb_26" for=":r13R1:">Reorder book</label></p><div><p class="_explain_6sh2w_146">Select the <strong>shelf</strong> with a<strong> frame</strong> followed by a <strong>purple book</strong></p><p class="_arrow_6sh2w_122"></p><p class="_code_6sh2w_114">.shelf:has(.frame + .book-purple)</p></div></div></astro-island>
  111. <h3 id="select-a-shelf-if-it-only-contains-a-box">Select a shelf if it only contains a box</h3>
  112. <p>In this example, the CSS <code>:has()</code> selector tries to match if there are books inside the box container only.</p>
  113. <astro-island uid="Z1POSdh" prefix="r14" component-url="/_astro/ShelfBox.CbGVwB2-.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"ElementFollowedBy2$3","value":true}' await-children=""><div class="example-wrapper center _wrapper_3yj15_1"><p class="_checkbox_4pedb_1 _mainColor_4pedb_4"><input id=":r14R1:" type="checkbox" class="_srOnly_4pedb_43 _input_4pedb_8"><label class="_label_4pedb_26" for=":r14R1:">Reorder book</label></p><div><p class="_explain_3yj15_181">Select the <strong>shelf</strong> that has a container of books</p><p class="_arrow_3yj15_157"></p></div></div></astro-island>
  114. <h3 id="select-a-box-without-a-blue-book">Select a box without a blue book</h3>
  115. <p>Combining <code>:has()</code> and <code>:not()</code> is one of the many possible things to do in CSS <code>:has()</code>. In this example, the selector will match only if the box <strong>doesn’t have a blue book</strong>.</p>
  116. <astro-island uid="2bFOkl" prefix="r15" component-url="/_astro/ShelfBox2.MkLtBXHq.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"ElementFollowedBy2$2","value":true}' await-children=""><div class="example-wrapper center _wrapper_urqi1_1"><p class="_checkbox_4pedb_1 _mainColor_4pedb_4"><input id=":r15R1:" type="checkbox" class="_srOnly_4pedb_43 _input_4pedb_8"><label class="_label_4pedb_26" for=":r15R1:">Remove blue book</label></p><div><p class="_explain_urqi1_180">Select the <strong>box</strong> that <strong>doesn't</strong> have a blue book</p><p class="_arrow_urqi1_156"></p></div></div></astro-island>
  117. <h3 id="select-the-box-with-3-books">Select the box with 3+ books</h3>
  118. <astro-island uid="Z1rz3U5" prefix="r16" component-url="/_astro/ShelfBox3.DPHxAJJs.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"ElementFollowedBy2$1","value":true}' await-children=""><div class="example-wrapper center _wrapper_e5jbw_1"><p class="_checkbox_4pedb_1 _mainColor_4pedb_4"><input id=":r16R1:" type="checkbox" class="_srOnly_4pedb_43 _input_4pedb_8"><label class="_label_4pedb_26" for=":r16R1:">Add book</label></p><div><p class="_explain_e5jbw_157">Select the <strong>.box</strong> with 3+ books</p><p class="_arrow_e5jbw_133"></p><div class="_code_e5jbw_125"><span>.box:has(.book:nth-last-child(n + 3))</span></div></div></div></astro-island>
  119. <h3 id="change-the-book-order-based-on-the-number">Change the book order based on the number</h3>
  120. <p>An interesting way is to change the book ordering from stacked to stand-up based on their number. In the following demo, if the number of books is 5+, they will change to a standing-up order.</p>
  121. <p>Try to add more books and see what happens.</p>
  122. <astro-island uid="Z1VMFF1" prefix="r17" component-url="/_astro/ShelfBox4.EuBXAB9S.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"ElementFollowedBy2","value":true}' await-children=""><div class="example-wrapper center _wrapper_e5jbw_1 _booksOrder_e5jbw_7 "><p class="demoActions"><button class="button button--add">Add</button><button class="button button-remove" disabled>Remove</button><button class="button button--reset">Reset</button></p><div><p class="_explain_e5jbw_157">Change books from <strong>stacking to standing</strong> if 5+</p><p class="_arrow_e5jbw_133"></p><div class="_code_e5jbw_125"><div><span>.shelf:has(.book:nth-last-child(n + 5))</span> <p> {</p><div><p>flex-direction: row;</p><div><p>.book {</p><div><p>height: 100%;</p><p>width: 22px;</p></div><p>}</p></div></div><p>}</p></div></div></div></div></astro-island>
  123. <p>By using the <code>:nth-last-child()</code>, this is possible.</p>
  124. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.shelf:has(.book:nth-last-child(n + 5))</span> <span class="token punctuation">{</span>
  125. <span class="token property">flex-direction</span><span class="token punctuation">:</span> row<span class="token punctuation">;</span>
  126. <span class="token selector">.book</span> <span class="token punctuation">{</span>
  127. <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
  128. <span class="token property">width</span><span class="token punctuation">:</span> 22px<span class="token punctuation">;</span>
  129. <span class="token punctuation">}</span>
  130. <span class="token punctuation">}</span></code></pre>
  131. <h3 id="add-spacing-to-each-3rd-items-if-5-books">Add spacing to each 3rd items if 5+ books</h3>
  132. <p>This is the same previous example, but we took it further. If the number of items is 5+ books, we need to add a space <strong>to each 3rd item</strong> for better shelf organization.</p>
  133. <astro-island uid="ZzB9PJ" prefix="r18" component-url="/_astro/ShelfBox4.EuBXAB9S.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"count":[0,5],"spacing":[0,true]}' ssr="" client="visible" opts='{"name":"ElementFollowedBy2","value":true}' await-children=""><div class="example-wrapper center _wrapper_e5jbw_1 _booksOrder_e5jbw_7 "><p class="demoActions"><button class="button button--add">Add</button><button class="button button-remove">Remove</button><button class="button button--reset">Reset</button></p><div><p class="_explain_e5jbw_157">Add spacing to each 3rd item if 5+ books</p><p class="_arrow_e5jbw_133"></p><div class="_code_e5jbw_125"><div><span>.shelf:has(.book:nth-last-child(n + 5))</span> <p> {</p><p>}</p></div></div></div></div></astro-island>
  134. <h3 id="the-bookshelf">The bookshelf</h3>
  135. <p>A fun example where I have the following conditions with CSS <code>:has()</code>:</p>
  136. <ul>
  137. <li>Change the books from stack to stand based on their number</li>
  138. <li>Hang the frame to the wall if certain number of books is there</li>
  139. <li>Throw the plant and earth on the ground</li>
  140. </ul>
  141. <p>Play with the demo.</p>
  142. <astro-island uid="1pgzNT" prefix="r19" component-url="/_astro/BookShelf.6cORX75g.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"BookShelf","value":true}' await-children=""></astro-island>
  143. <h4 id="change-books-ordering">Change books ordering</h4>
  144. <p>The first thing is that I want to change the books from stack to stand, if there are 5+ books.</p>
  145. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.shelf:has(.book:nth-last-of-type(n + 5))</span> <span class="token punctuation">{</span>
  146. <span class="token property">flex-direction</span><span class="token punctuation">:</span> row<span class="token punctuation">;</span>
  147. <span class="token selector">.book</span> <span class="token punctuation">{</span>
  148. <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
  149. <span class="token property">width</span><span class="token punctuation">:</span> 22px<span class="token punctuation">;</span>
  150. <span class="token punctuation">}</span>
  151. <span class="token punctuation">}</span></code></pre>
  152. <h4 id="hang-the-frame-to-the-wall">Hang the frame to the wall</h4>
  153. <p>If there 6+ books, the frame should be moved to the wall.</p>
  154. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.shelf:has(.book:nth-last-of-type(n + 6))</span> <span class="token punctuation">{</span>
  155. <span class="token selector">.frame</span> <span class="token punctuation">{</span>
  156. <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
  157. <span class="token property">left</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>50% - <span class="token punctuation">(</span>75px / 2<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  158. <span class="token property">top</span><span class="token punctuation">:</span> -165%<span class="token punctuation">;</span>
  159. <span class="token punctuation">}</span>
  160. <span class="token punctuation">}</span></code></pre>
  161. <h4 id="throw-the-plant-and-earth">Throw the plant and earth</h4>
  162. <p>No space at all? Simple, throw the plant and earth to the ground, but I’m not responsible for any mess.</p>
  163. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.shelf:has(.book:nth-last-of-type(n + 9))</span> <span class="token punctuation">{</span>
  164. <span class="token selector">.plant</span> <span class="token punctuation">{</span>
  165. <span class="token property">animation</span><span class="token punctuation">:</span> movePlant 0.6s forwards<span class="token punctuation">;</span>
  166. <span class="token punctuation">}</span>
  167. <span class="token selector">.earth</span> <span class="token punctuation">{</span>
  168. <span class="token property">animation</span><span class="token punctuation">:</span> moveEarth 0.6s forwards<span class="token punctuation">;</span>
  169. <span class="token punctuation">}</span>
  170. <span class="token punctuation">}</span></code></pre>
  171. <h3 id="logical-operators-with-css-has">Logical operators with CSS :has</h3>
  172. <p>With CSS <code>:has()</code>, we can replicate the logical operators like ”&amp;&amp;” and ”||“. In the following demo, we have the conditions:</p>
  173. <ul>
  174. <li>Select the shelf if it contains the purple <strong>and</strong> yellow book.</li>
  175. <li>Select the shelf if it contains the purple <strong>or</strong> the yellow book.</li>
  176. </ul>
  177. <p>Try the following:</p>
  178. <ul>
  179. <li>Toggle the books on or off</li>
  180. <li>Change the option in the menu between “and” / “or”</li>
  181. </ul>
  182. <astro-island uid="21WFsG" prefix="r20" component-url="/_astro/ShelfOrAnd.BCTmdOx6.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"ShelfOrAnd$1","value":true}' await-children=""><div class="example-wrapper center _wrapper_1d5r1_1"><div><p class="_explain_1d5r1_139">Select the shelf that has the <strong>purple</strong> book <select name="logicalOperator" id="logicalOperator"><option value="and" selected>and</option><option value="or">or</option></select>the <strong>yellow</strong> book</p><p class="_arrow_1d5r1_115"></p><div class="_code_1d5r1_107"><div><span>.shelf:has(.book-purple):has(.book-yellow)</span> <p> {</p><p>outline: dashed 2px deeppink;</p><p>}</p></div></div></div></div></astro-island>
  183. <p>In CSS, here is what’s happening:</p>
  184. <pre class="language-css"><code is:raw="" class="language-css">
  185. <span class="token selector">.shelf:has(.bookPurple, .bookYellow)</span> <span class="token punctuation">{</span>
  186. <span class="token property">outline</span><span class="token punctuation">:</span> dashed 2px deeppink<span class="token punctuation">;</span>
  187. <span class="token punctuation">}</span>
  188. <span class="token selector">.shelf:has(.bookPurple):has(.bookYellow)</span> <span class="token punctuation">{</span>
  189. <span class="token property">outline</span><span class="token punctuation">:</span> dashed 2px deeppink<span class="token punctuation">;</span>
  190. <span class="token punctuation">}</span></code></pre>
  191. <p>It’s amazing what we can do with logical operators in CSS <code>:has()</code>.</p>
  192. <p>I hope that you learned how the CSS <code>:has()</code> works. Now, let’s move into interesting use cases for CSS <code>:has()</code>.</p>
  193. <h2 id="use-cases-for-css-has">Use cases for CSS :has</h2>
  194. <h3 id="file-download">File download</h3>
  195. <p>This is one of my favorite use cases in this article. Say we have a file component that shows the following:</p>
  196. <ul>
  197. <li>File image</li>
  198. <li>Name</li>
  199. <li>Meta info (pages, size, etc)</li>
  200. </ul>
  201. <p>If there is no image for the file, we want to check the file extension and change the icon. We can do that with <code>:has()</code>.</p>
  202. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.file:not(:has(img)) .thumb:before</span> <span class="token punctuation">{</span>
  203. <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">;</span>
  204. <span class="token property">background-image</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--bg<span class="token punctuation">,</span> initial<span class="token punctuation">)</span><span class="token punctuation">;</span>
  205. <span class="token punctuation">}</span>
  206. <span class="token selector">.file:has([href$=".pdf"])</span> <span class="token punctuation">{</span>
  207. <span class="token property">--bg</span><span class="token punctuation">:</span> <span class="token string">"icon-pdf.png"</span><span class="token punctuation">;</span>
  208. <span class="token punctuation">}</span>
  209. </code></pre>
  210. <p>Try to toggle the image, then change the file type and see what happens. This is magic, isn’t it?</p>
  211. <astro-island uid="XYVDc" prefix="r21" component-url="/_astro/FileDownload.DkLT1KdO.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"FileDownload","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_207mc_1"><div class="_code_207mc_63"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">file</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">thumb</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">file.docx</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  212. <p>What if we have a sidebar and need to increase its width if it contains a widget? This is possible with CSS :has.</p>
  213. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.layout</span> <span class="token punctuation">{</span>
  214. <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  215. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> max-content 1fr<span class="token punctuation">;</span>
  216. <span class="token punctuation">}</span>
  217. <span class="token selector">.sidebar:has(.widget)</span> <span class="token punctuation">{</span>
  218. <span class="token property">width</span><span class="token punctuation">:</span> 180px<span class="token punctuation">;</span>
  219. <span class="token punctuation">}</span></code></pre>
  220. <p>Try it in the interactive demo. I recommend to view this on a large screen.</p>
  221. <astro-island uid="1sVt7" prefix="r22" component-url="/_astro/SidebarWidth.h7JOmyL_.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"SidebarWidth$2","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_17qqr_1 "><div class="_page_17qqr_10"><div><p>Please fill the following:</p></div></div><div class="_code_17qqr_49"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">page</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">sidebar</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">h2</span><span class="token tag punctuation">&gt;</span><span class="token plain">Selected period</span><span class="token tag punctuation">&lt;/</span><span class="token tag">h2</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">widget</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">main</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  222. <h3 id="cookies-banner">Cookies Banner</h3>
  223. <p>This is a common layout issue that I see a lot. Say you have an Intercom widget, and a cookies banner. How the UI will react?</p>
  224. <p>Toggle the banner in the demo below. Notice how the widget is hidden under the banner. This isn’t good.</p>
  225. <astro-island uid="Z1pYES7" prefix="r23" component-url="/_astro/CookiesBanner.WIZzp-jB.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"1"]}' ssr="" client="visible" opts='{"name":"SidebarWidth$1","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_1mmo4_1 false"><p>CSS is awesome. Isn't it?</p><p class="_fab_1mmo4_11"></p></div></div></astro-island>
  226. <p>We can use CSS <code>:has()</code> to move the widget <strong>if the banner is shown</strong>.</p>
  227. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">body:has(.banner) .fab</span> <span class="token punctuation">{</span>
  228. <span class="token property">bottom</span><span class="token punctuation">:</span> 6rem<span class="token punctuation">;</span>
  229. <span class="token punctuation">}</span></code></pre>
  230. <p>Play with the demo and toggle the CSS <code>:has()</code> checkbox.</p>
  231. <astro-island uid="21jY1k" prefix="r24" component-url="/_astro/CookiesBanner.WIZzp-jB.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"2"]}' ssr="" client="visible" opts='{"name":"SidebarWidth$1","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_1mmo4_1 false"><p>CSS is awesome. Isn't it?</p><p class="_fab_1mmo4_11"></p></div></div></astro-island>
  232. <h3 id="dashboard-banner">Dashboard banner</h3>
  233. <p>In this example, I want to show an additional visual clue if the page has an alert.</p>
  234. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.main:has(.alert) .header</span> <span class="token punctuation">{</span>
  235. <span class="token property">box-shadow</span><span class="token punctuation">:</span>
  236. inset 0 2px 0 0 red<span class="token punctuation">,</span>
  237. 0 3px 10px 0 <span class="token function">rgba</span><span class="token punctuation">(</span>#000<span class="token punctuation">,</span> 0.1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  238. <span class="token property">background-color</span><span class="token punctuation">:</span> #fff4f4<span class="token punctuation">;</span>
  239. <span class="token punctuation">}</span></code></pre>
  240. <p>Toggle the alert and what happens.</p>
  241. <astro-island uid="1Cv1oD" prefix="r25" component-url="/_astro/DashboardBanner.DCdYFunL.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"SidebarWidth","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_18ys2_1 false"><div class="_parent_18ys2_12"><div class="_main_18ys2_34"><div class="_alert_18ys2_47"><svg version="1.1" viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path d="m98.715 83.008l-43.457-70.844c-2.8906-4.7227-7.625-4.6562-10.516 0.066407l-43.457 70.746c-2.8906 4.7227-0.73047 8.3711 4.8008 8.3711h87.824c5.5352 0 7.6953-3.625 4.8047-8.3398zm-48.75-55.164c2.7812 0 4.9375 3.0742 4.793 6.832l-0.88281 22.641c-0.14062 3.7539-1.9102 6.8281-3.9219 6.8281-2.0156 0-3.7852-3.0742-3.9258-6.8281l-0.87109-22.641c-0.14062-3.7578 2.0195-6.832 4.8086-6.832zm0 53.355c-3.5117 0-5.9219-2.5664-5.8477-6.0742 0-3.5859 2.4141-6.0742 5.8477-6.0742 3.5781 0 5.8398 2.4922 5.918 6.0742-0.003906 3.5078-2.3398 6.0742-5.918 6.0742z"></path></svg><p>Something is wrong. Please fix here!</p></div></div></div></div></div></astro-island>
  242. <h3 id="quantity-queries-with-css-has">Quantity queries with CSS :has</h3>
  243. <p>I first learned about quantity queries via <a href="https://alistapart.com/article/quantity-queries-for-css/">this article</a> by Heydon Pickering on A List Apart. The good thing is that we can use them with CSS <code>:has()</code>.</p>
  244. <p>The idea is to use the CSS <code>:nth-last-child</code> like this:</p>
  245. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">li:nth-last-child(n + 5),
  246. li:nth-last-child(n + 5) ~ li</span> <span class="token punctuation">{</span>
  247. <span class="token property">width</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span>
  248. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  249. <span class="token property">flex-direciton</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span>
  250. <span class="token punctuation">}</span></code></pre>
  251. <p>This will select all <code>&lt;li&gt;</code>s if there are 5 or more. The problem is that it’s limited to the child elements only. We can’t select the parent.</p>
  252. <p>With CSS <code>:has()</code>, this is possible.</p>
  253. <p>Here is an example:</p>
  254. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.wrapper</span> <span class="token punctuation">{</span>
  255. <span class="token property">--item-size</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span>
  256. <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  257. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>
  258. auto-fit<span class="token punctuation">,</span>
  259. <span class="token function">minmax</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--item-size<span class="token punctuation">)</span><span class="token punctuation">,</span> 1fr<span class="token punctuation">)</span>
  260. <span class="token punctuation">)</span><span class="token punctuation">;</span>
  261. <span class="token property">gap</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  262. <span class="token punctuation">}</span>
  263. <span class="token selector">.wrapper:has(li:nth-last-child(n + 5))</span> <span class="token punctuation">{</span>
  264. <span class="token property">--item-size</span><span class="token punctuation">:</span> 200px<span class="token punctuation">;</span>
  265. <span class="token punctuation">}</span></code></pre>
  266. <p>I used a CSS variable to represent the item width in the <code>minmax()</code> function. Let’s play with that in CSS <code>:has()</code>.</p>
  267. <p>See the interactive demo below. Here is what’s happening:</p>
  268. <ul>
  269. <li>There is a quantity query with CSS <code>:has()</code>. I have 3 of them.</li>
  270. <li>When the number of items changes, the matching query will work.</li>
  271. </ul>
  272. <astro-island uid="Z2phmPM" prefix="r26" component-url="/_astro/QuantityQueries.BywiYCjI.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"ShelfOrAnd","value":true}' await-children=""><div class="example-wrapper center _wrapper_1lzv4_1"><p class="_demoActions_1lzv4_52"><button class="button button--add">Add</button><button class="button button-remove" disabled>Remove</button><button class="button button--reset">Reset</button></p><div><div class="_code_1lzv4_10"><div><span>.wrapper:has(li:nth-last-child(<strong>n + 3</strong>))</span><p> {</p><p>--item-size: 220px;</p><p>}</p></div><div><span>.wrapper:has(li:nth-last-child(<strong>n + 6</strong>))</span><p> {</p><p>--item-size: 170px;</p><p>}</p></div><div><span>.wrapper:has(li:nth-last-child(<strong>n + 9</strong>))</span><p> {</p><p>--item-size: 130px;</p><p>}</p></div></div></div></div></astro-island>
  273. <h3 id="select-title-that-comes-after-a-link">Select title that comes after a link</h3>
  274. <p>We can select an element if it’s followed by another. In this example, I want to select the <code>&lt;a&gt;</code> only if it’s followed by <code>&lt;h3&gt;</code>.</p>
  275. <p>Without CSS <code>:has()</code>, we’re limited to the following only:</p>
  276. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.prose a + h3</span> <span class="token punctuation">{</span>
  277. <span class="token punctuation">}</span></code></pre>
  278. <p>With CSS <code>:has()</code>, we can straightforwardly do that.</p>
  279. <pre class="language-css"><code is:raw="" class="language-css">
  280. <span class="token selector">a:has(+ h3)</span> <span class="token punctuation">{</span>
  281. <span class="token property">display</span><span class="token punctuation">:</span> inline-flex<span class="token punctuation">;</span>
  282. <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand-1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  283. <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  284. <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem 1rem<span class="token punctuation">;</span>
  285. <span class="token property">border-radius</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
  286. <span class="token punctuation">}</span></code></pre>
  287. <p>Play with the interactive demo below.</p>
  288. <astro-island uid="Z1ytRmk" prefix="r27" component-url="/_astro/ElementFollowedBy.DkOn4VO8.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"ElementFollowedBy","value":true}' await-children=""><div class="example-wrapper center _wrapper_1uclk_1"><div class="_innerContent_1uclk_13"><div><p class="_explain_1uclk_20">select all <strong>a</strong> that have<strong> h3</strong> directly after it</p><p class="_arrow_1uclk_32"></p></div><div class="_liveExample_1uclk_56"><div><p class="_tag_1uclk_106">HTML</p><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">prose</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">h2</span><span class="token tag"> </span><span class="token tag punctuation">&gt;</span><span class="token plain">Main heading</span><span class="token tag punctuation">&lt;/</span><span class="token tag">h2</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain">Description text</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">#</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain">Read more here</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain">CSS is awesome.</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">h3</span><span class="token tag punctuation">&gt;</span><span class="token plain">Sub title in here</span><span class="token tag punctuation">&lt;/</span><span class="token tag">h3</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span></p></pre></div><div class="_sample_1uclk_75"><p class="_tag_1uclk_106">Result</p><h2 aria-hidden="true">Main heading</h2><p>Description text</p><a href="#">Read more here</a><p>CSS is awesome.</p><h3 aria-hidden="true">[h3] Sub title in here</h3></div></div></div></div></astro-island>
  289. <h3 id="card-with-a-disabled-button">Card with a disabled button</h3>
  290. <p>In this example, we have a product card with a stock element. When the stock element has the class of <code>.out-of-stock</code>, we want to change the card style.</p>
  291. <p>We can hide the “add to cart” button, or show a “Notify me when available”. Whatever works best for your case.</p>
  292. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.card:has(.out-of-stock) .button</span> <span class="token punctuation">{</span>
  293. <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
  294. <span class="token punctuation">}</span></code></pre>
  295. <astro-island uid="kODDX" prefix="r28" component-url="/_astro/CardDisabled.Do4Ehjqk.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"1"]}' ssr="" client="visible" opts='{"name":"CardDisabled","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_1eq8w_1"><p>Toggle the checkbox.</p><article class="_card_1eq8w_10"><img src="/assets/css-has-guide/tart.jpeg" alt=""><div><h3>The Barista Pro</h3><p>Be a barista at home.</p><p class="false">5 items left</p><a href="#" class="_button_1eq8w_40">Add to cart</a></div></article></div></div></astro-island>
  296. <p>Another option for the same case is to add a tag at the top of the product card. Those are purely design decisions and the demo just showcases one of the many possible solutions.</p>
  297. <pre class="language-scss"><code is:raw="" class="language-scss"><span class="token selector">.card </span><span class="token punctuation">{</span>
  298. &amp;<span class="token punctuation">:</span><span class="token function">has</span><span class="token punctuation">(</span>.outOfStock<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  299. <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span>
  300. <span class="token selector"><span class="token parent important">&amp;</span>:after </span><span class="token punctuation">{</span>
  301. <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">"Not available"</span><span class="token punctuation">;</span>
  302. <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
  303. <span class="token property">inset-inline</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
  304. <span class="token property">top</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
  305. <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  306. <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgb</span><span class="token punctuation">(</span>255 0 0 <span class="token operator">/</span> 76%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  307. <span class="token punctuation">}</span>
  308. <span class="token punctuation">}</span>
  309. <span class="token punctuation">}</span></code></pre>
  310. <p>Try to toggle “out of stock” and see what happens.</p>
  311. <astro-island uid="Z26mAbr" prefix="r29" component-url="/_astro/CardDisabled.Do4Ehjqk.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"2"]}' ssr="" client="visible" opts='{"name":"CardDisabled","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_1eq8w_1"><p>Toggle the checkbox.</p><article class="_card_1eq8w_10 _card2_1eq8w_44"><img src="/assets/css-has-guide/tart.jpeg" alt=""><div><h3>The Barista Pro</h3><p>Be a barista at home.</p><p class="false">5 items left</p></div></article></div></div></astro-island>
  312. <h3 id="card-with-hovered-button">Card with hovered button</h3>
  313. <p>We can add a hover effect to a card if a button is hovered.</p>
  314. <p>Try to hover on the button and see how the card shadow changes. This is all with CSS <code>:has()</code>.</p>
  315. <astro-island uid="Z28aJ7i" prefix="r30" component-url="/_astro/CardDisabled.Do4Ehjqk.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"3"]}' ssr="" client="visible" opts='{"name":"CardDisabled","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_1eq8w_1"><article class="_card_1eq8w_10 _card3_1eq8w_86 null"><img src="/assets/css-has-guide/tart.jpeg" alt=""></article><p>Try to hover on the button</p></div></div></astro-island>
  316. <p>For me, this is like <code>:focus-within</code>. Maybe I should call it <code>:hover-within</code>?</p>
  317. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.card:has(.button:hover)</span> <span class="token punctuation">{</span>
  318. <span class="token property">box-shadow</span><span class="token punctuation">:</span>
  319. 0 2px 4px 0 <span class="token function">rgba</span><span class="token punctuation">(</span>#000<span class="token punctuation">,</span> 0.15<span class="token punctuation">)</span><span class="token punctuation">,</span>
  320. 0 3px 25px 0 <span class="token function">rgba</span><span class="token punctuation">(</span>#000<span class="token punctuation">,</span> 0.15<span class="token punctuation">)</span><span class="token punctuation">;</span>
  321. <span class="token punctuation">}</span></code></pre>
  322. <p>Toggle the 2nd style and see a different styling option. This is all done with CSS <code>:has()</code>.</p>
  323. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  324. <span class="token selector">&amp;:has(.button:hover)</span> <span class="token punctuation">{</span>
  325. <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  326. <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand-1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  327. <span class="token property">box-shadow</span><span class="token punctuation">:</span>
  328. 0 0 0 7px <span class="token function">var</span><span class="token punctuation">(</span>--brand-1<span class="token punctuation">)</span><span class="token punctuation">,</span>
  329. 0 2px 20px 0 <span class="token function">rgba</span><span class="token punctuation">(</span>#000<span class="token punctuation">,</span> 0.25<span class="token punctuation">)</span><span class="token punctuation">,</span>
  330. 0 3px 45px 0 <span class="token function">rgba</span><span class="token punctuation">(</span>#000<span class="token punctuation">,</span> 0.25<span class="token punctuation">)</span><span class="token punctuation">;</span>
  331. <span class="token selector">.button</span> <span class="token punctuation">{</span>
  332. <span class="token property">color</span><span class="token punctuation">:</span> inherit<span class="token punctuation">;</span>
  333. <span class="token punctuation">}</span>
  334. <span class="token selector">h3,
  335. p</span> <span class="token punctuation">{</span>
  336. <span class="token property">color</span><span class="token punctuation">:</span> inherit<span class="token punctuation">;</span>
  337. <span class="token punctuation">}</span>
  338. <span class="token punctuation">}</span>
  339. <span class="token punctuation">}</span></code></pre>
  340. <h3 id="modal">Modal</h3>
  341. <p>In a modal, we might need to change the title color if it’s about a critical action, like deleting something important.</p>
  342. <p>See the following demo. We have a modal with action buttons.</p>
  343. <astro-island uid="Z1CvVTT" prefix="r31" component-url="/_astro/Modal.Bm56Jn-T.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"Modal$3","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_sk8rm_1 undefined"><div class="_modal_sk8rm_11"><div class="_modalContent_sk8rm_65"><p>Are you sure you want to save the changes?</p><p>This cannot be undone.</p></div></div></div></div></astro-island>
  344. <p>What I want is that when there is a <code>.btn--danger</code> class, the modal title should be red. Normally, we’ll need to add a class like this to the modal header:</p>
  345. <pre class="language-html"><code is:raw="" class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>modal modal--danger<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  346. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>modal-header<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  347. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span>Edit project<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
  348. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  349. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span></code></pre>
  350. <p>And then style it like so:</p>
  351. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.modal--danger h2</span> <span class="token punctuation">{</span>
  352. <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
  353. <span class="token punctuation">}</span></code></pre>
  354. <p>With CSS <code>:has()</code>, all we need to do is the following:</p>
  355. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.modal</span> <span class="token punctuation">{</span>
  356. <span class="token selector">&amp;:has(.btn--danger)</span> <span class="token punctuation">{</span>
  357. <span class="token selector">.modal-title</span> <span class="token punctuation">{</span>
  358. <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
  359. <span class="token punctuation">}</span>
  360. <span class="token punctuation">}</span>
  361. <span class="token punctuation">}</span></code></pre>
  362. <p>See the interactive demo.</p>
  363. <astro-island uid="ZKyWBJ" prefix="r32" component-url="/_astro/Modal.Bm56Jn-T.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"interactive":[0,true]}' ssr="" client="visible" opts='{"name":"Modal$3","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_sk8rm_1 _interactive_sk8rm_7"><div class="_modal_sk8rm_11"><div class="_modalContent_sk8rm_65"><p>Are you sure you want to save the changes?</p><p>This cannot be undone.</p></div></div></div></div></astro-island>
  364. <h3 id="modal-buttons">Modal buttons</h3>
  365. <p>In this example, we have a modal with multiple action buttons. The problem here is that we want to change the layout based on the number of buttons.</p>
  366. <p>Try to toggle the checkbox and see what happens.</p>
  367. <astro-island uid="1iExxb" prefix="r33" component-url="/_astro/Modal2.C8DdRMqa.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"interactive":[0,true]}' ssr="" client="visible" opts='{"name":"Modal$2","value":true}' await-children=""></astro-island>
  368. <p>Notice how the layout changed? This happened with CSS <code>:has()</code> only. It’s wild of what we can do with it!</p>
  369. <p>See the following HTML.</p>
  370. <pre class="language-html"><code is:raw="" class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>modal-actions<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  371. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn--secondary<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Cancel<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span>
  372. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn--ter<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Save draft<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span>
  373. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn btn--primary<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">&gt;</span></span>
  374. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span></code></pre>
  375. <p>In CSS, we need to check if the number of buttons is three. If yes:</p>
  376. <ul>
  377. <li>position the last one on the far right</li>
  378. <li>change <code>justify-content</code> to <code>stretch</code></li>
  379. </ul>
  380. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.modal-actions</span> <span class="token punctuation">{</span>
  381. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  382. <span class="token property">justify-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  383. <span class="token property">gap</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  384. <span class="token selector">&amp;:has(.btn:nth-last-child(n + 3))</span> <span class="token punctuation">{</span>
  385. <span class="token property">justify-content</span><span class="token punctuation">:</span> stretch<span class="token punctuation">;</span>
  386. <span class="token selector">.btn:last-child</span> <span class="token punctuation">{</span>
  387. <span class="token property">margin-inline-start</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
  388. <span class="token punctuation">}</span>
  389. <span class="token punctuation">}</span>
  390. <span class="token punctuation">}</span></code></pre>
  391. <p>We can even go further and make more styling changes. For example:</p>
  392. <ul>
  393. <li>Change the background color</li>
  394. <li>Add a border</li>
  395. <li>Add padding</li>
  396. <li>Reset paddings with negative margins (kind of a hack)</li>
  397. </ul>
  398. <astro-island uid="2dKyYd" prefix="r34" component-url="/_astro/Modal2.C8DdRMqa.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"interactive":[0,true],"style2":[0,true]}' ssr="" client="visible" opts='{"name":"Modal$2","value":true}' await-children=""></astro-island>
  399. <p>Here is the CSS:</p>
  400. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.modal-actions</span> <span class="token punctuation">{</span>
  401. <span class="token selector">&amp;:has(.btn:nth-last-child(n + 3))</span> <span class="token punctuation">{</span>
  402. <span class="token property">justify-content</span><span class="token punctuation">:</span> stretch<span class="token punctuation">;</span>
  403. <span class="token property">border-top</span><span class="token punctuation">:</span> 1px solid #d3d3d3<span class="token punctuation">;</span>
  404. <span class="token property">background-color</span><span class="token punctuation">:</span> #f5f5f5<span class="token punctuation">;</span>
  405. <span class="token property">padding</span><span class="token punctuation">:</span> 0.75rem<span class="token punctuation">;</span>
  406. <span class="token property">margin-inline</span><span class="token punctuation">:</span> -1rem<span class="token punctuation">;</span>
  407. <span class="token property">margin-bottom</span><span class="token punctuation">:</span> -1rem<span class="token punctuation">;</span>
  408. <span class="token selector">.btn:last-child</span> <span class="token punctuation">{</span>
  409. <span class="token property">margin-inline-start</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
  410. <span class="token punctuation">}</span>
  411. <span class="token punctuation">}</span>
  412. <span class="token punctuation">}</span></code></pre>
  413. <h3 id="section-empty-state">Section empty state</h3>
  414. <p>In this example, CSS <code>:has()</code> is used to detect if a section contains an element with empty content. If yes, then the layout will change.</p>
  415. <p>Before CSS <code>:has()</code>, this needed to be done in Javascript. Now, with CSS <code>:has()</code> help, we can reduce the Javascript needed significantly.</p>
  416. <p>Here is the section with the content.</p>
  417. <astro-island uid="ZklAV1" prefix="r35" component-url="/_astro/SectionEmpty.CR93UmMt.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"default":[0,true]}' ssr="" client="visible" opts='{"name":"Modal$1","value":true}' await-children=""></astro-island>
  418. <p>When there is no content, it should look like this:</p>
  419. <astro-island uid="Z275cRA" prefix="r36" component-url="/_astro/SectionEmpty.CR93UmMt.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"empty":[0,true]}' ssr="" client="visible" opts='{"name":"Modal$1","value":true}' await-children=""></astro-island>
  420. <p>We can check the <code>:empty</code> pseudo-class on the parent and do the styles we need.</p>
  421. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.section:has(.sectionContent:empty)</span> <span class="token punctuation">{</span>
  422. <span class="token punctuation">}</span></code></pre>
  423. <p>Here is the complete CSS:</p>
  424. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.section:has(.sectionContent:empty)</span> <span class="token punctuation">{</span>
  425. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  426. <span class="token property">flex-direction</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span>
  427. <span class="token property">justify-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  428. <span class="token property">min-height</span><span class="token punctuation">:</span> 150px<span class="token punctuation">;</span>
  429. <span class="token selector">.sectionHeader</span> <span class="token punctuation">{</span>
  430. <span class="token selector">p:first-child</span> <span class="token punctuation">{</span>
  431. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  432. <span class="token property">flex-direction</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span>
  433. <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  434. <span class="token property">gap</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  435. <span class="token selector">&amp;:before</span> <span class="token punctuation">{</span>
  436. <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">;</span>
  437. <span class="token property">--size</span><span class="token punctuation">:</span> 3rem<span class="token punctuation">;</span>
  438. <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span>
  439. <span class="token property">width</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--size<span class="token punctuation">)</span><span class="token punctuation">;</span>
  440. <span class="token property">height</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--size<span class="token punctuation">)</span><span class="token punctuation">;</span>
  441. <span class="token property">background-color</span><span class="token punctuation">:</span> lightblue<span class="token punctuation">;</span>
  442. <span class="token property">border-radius</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span>
  443. <span class="token punctuation">}</span>
  444. <span class="token punctuation">}</span>
  445. <span class="token selector">p:last-child</span> <span class="token punctuation">{</span>
  446. <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span>
  447. <span class="token punctuation">}</span>
  448. <span class="token punctuation">}</span>
  449. <span class="token punctuation">}</span></code></pre>
  450. <p>Play with the demo below.</p>
  451. <astro-island uid="Z2ta7L1" prefix="r37" component-url="/_astro/SectionEmpty.CR93UmMt.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"interactive":[0,true]}' ssr="" client="visible" opts='{"name":"Modal$1","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_tkj3d_1 _interactive_tkj3d_8"><div><div><span>.section:has(.sectionContent:empty)</span> <p> {</p><p>outline: dashed 2px deeppink;</p><p>}</p></div></div></div></div></astro-island>
  452. <h3 id="input-states">Input states</h3>
  453. <p>With CSS <code>:has()</code>, we can check the input state like a checkbox, radio button or <code>&lt;select&gt;</code> menus. There are some interesting use cases when mixing <code>:has()</code> with input states.</p>
  454. <h4 id="checkbox-and-css-has">Checkbox and CSS :has</h4>
  455. <p>We can check the value of a checkbox and do something as a result of it. See the following demo:</p>
  456. <p>If the checkbox is checked, the button will be enabled.</p>
  457. <astro-island uid="ZFqPcQ" prefix="r38" component-url="/_astro/InputStates.B_nBqO_a.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"checkbox"]}' ssr="" client="visible" opts='{"name":"InputStates","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_y6q5u_2 _wrapper1_y6q5u_7"><p><span aria-hidden="true">💡</span> Try to hover on the box or the button.</p><div><span><span><span data-name="box">.box</span>:has(input[type="checkbox"]:checked)</span></span> <p> {</p><div><div><p>.btn {</p><div><p>opacity: 1;</p><p>pointer-events: initial;</p></div><p>}</p></div></div><p>}</p></div><div data-name="box" class="_box_y6q5u_45 undefined"><div><p class="_title_y6q5u_62">Terms and conditions</p><p class="_desc_y6q5u_66">Before moving to the next step, please make sure you agree with our terms of services.</p></div><p><input type="checkbox" id=":"><label for=":">I accept the terms and conditions</label></p><a href="#" class="_btn_y6q5u_54 _btnPrimary_y6q5u_166">Next</a></div></div></div></astro-island>
  458. <p>It’s like an if statement in Javascript, or a React state. Interesting, right?</p>
  459. <h4 id="radio-button-and-css-has">Radio button and CSS :has</h4>
  460. <p>What if we want to change the CSS based on the selected radio button? This is also possible. In the following example, a note will be displayed if the user picks “standard shipping”.</p>
  461. <p>See the following demo:</p>
  462. <astro-island uid="ZiFbx1" prefix="r39" component-url="/_astro/InputStates.B_nBqO_a.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"radio"]}' ssr="" client="visible" opts='{"name":"InputStates","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_y6q5u_2 _wrapper2_y6q5u_15"><p><span aria-hidden="true">💡</span> Try to hover on the box or the button.</p><div><span><span><span data-name="box">.box</span>:has(input[value="standard"]:checked)</span></span> <p> {</p><p>}</p></div></div></div></astro-island>
  463. <h3 id="select-menu-and-css-has">Select menu and CSS :has</h3>
  464. <p>We can also check the currently selected option of a <code>&lt;select&gt;</code>. One common example is to display an input field conditionally.</p>
  465. <p>For example, if the user selects “other”, we want to show input to let them fill in more info.</p>
  466. <astro-island uid="28yjIh" prefix="r40" component-url="/_astro/InputStates.B_nBqO_a.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"select"]}' ssr="" client="visible" opts='{"name":"InputStates","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_y6q5u_2 _wrapper3_y6q5u_23"><div><span><span><span data-name="box">.box</span>:has(option[value="2"]:checked)</span></span> <p> {</p><p>}</p></div><div data-name="box" class="_box_y6q5u_45 _box3_y6q5u_87"><div><p class="_title_y6q5u_62">Tell us a bit about you</p><p class="_desc_y6q5u_66">Pick a delivery option.</p></div><p><label for="0">What do you prefer?</label><select id="0"><option value="1">Default</option><option value="2">Medium</option><option value="3">Other</option></select></p><p class="_other_y6q5u_87"><label for="">Other</label><input type="text" name="" id=""></p><a href="#" class="_btn_y6q5u_54 _btnPrimary_y6q5u_166">Next</a></div></div></div></astro-island>
  467. <h3 id="html-attributes">HTML attributes</h3>
  468. <h4 id="disabled-attribute">Disabled attribute</h4>
  469. <p>If a button has the <code>disabled</code> attribute, we can show additional information to let the user understand that something is missing.</p>
  470. <astro-island uid="Z1a2AxX" prefix="r41" component-url="/_astro/InputStates.B_nBqO_a.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"disabled"]}' ssr="" client="visible" opts='{"name":"InputStates","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_y6q5u_2 _wrapper4_y6q5u_34"><div><span><span><span data-name="disabled">.box</span>:has(button[disabled])</span></span> <p> {</p><p>}</p></div><div data-name="disabled" class="_box_y6q5u_45 _box4_y6q5u_98"><div><p class="_title_y6q5u_62">Create a new profile</p><p class="_desc_y6q5u_66 _desc1_y6q5u_123">Pick a delivery option.</p><p class="_desc_y6q5u_66 _desc2_y6q5u_126">Before creating a profile, you must verify your account first. Kindly check your email.</p></div><div><button class="_btn_y6q5u_54 _btnPrimary_y6q5u_166">Continue</button><p class="_note_y6q5u_77">You cannot create a profile.</p></div></div></div></div></astro-island>
  471. <p>This example is inspired by this <a href="https://www.smashingmagazine.com/2021/08/frustrating-design-patterns-disabled-buttons/">Great article</a> by Vitaly Friedman on Smashing Magazine.</p>
  472. <h4 id="dual-hover-with-data-attributes-and-has">Dual hover with data attributes and :has</h4>
  473. <p>By combining data attributes and CSS <code>:has()</code>, we can create a really interesting effect. You can trigger an item by hovering on another and they don’t need to be in the same parent.</p>
  474. <p>I first saw this by <a href="https://twitter.com/pomber/status/1739617079404134821">Rodrigo Pombo</a> and I was like 😱.</p>
  475. <p>The idea is to add a data attribute for two elements or more, and then use <code>:has()</code> to know when one of the items is hovered and trigger other items with the same data attribute.</p>
  476. <pre class="language-html"><code is:raw="" class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>wrapper<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  477. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>tags<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  478. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">data-name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>css<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>CSS<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
  479. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span> <span class="token attr-name">data-name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>design<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Design<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
  480. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
  481. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
  482. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>article</span> <span class="token attr-name">data-name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>css<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>article</span><span class="token punctuation">&gt;</span></span>
  483. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>article</span> <span class="token attr-name">data-name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>design<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>article</span><span class="token punctuation">&gt;</span></span>
  484. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  485. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span></code></pre>
  486. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.wrapper:has([data-name="css"]:hover) [data-name="css"]</span> <span class="token punctuation">{</span>
  487. <span class="token property">outline</span><span class="token punctuation">:</span> 2px solid<span class="token punctuation">;</span>
  488. <span class="token punctuation">}</span></code></pre>
  489. <p>See the following demo:</p>
  490. <astro-island uid="N3O4F" prefix="r53" component-url="/_astro/HTMLAttr.C-i5Z4NH.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props='{"variation":[0,"data-attr"]}' ssr="" client="visible" opts='{"name":"HTMLAttr$1","value":true}' await-children=""></astro-island>
  491. <h4 id="dual-hover-example">Dual hover example</h4>
  492. <p>Say we have a widget that contains a sample of my work. I want to have links to each and at the same time to connect the items to images. We can add the images as pseudo-elements, but that is a hack.</p>
  493. <p>With CSS <code>:has()</code>, we can have the images in a separate element and add a shared data attribute for each link and image.</p>
  494. <pre class="language-html"><code is:raw="" class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>work<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  495. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>
  496. I wrote a book on
  497. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">data-name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://debuggingcss.com/<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  498. Debugging CSS <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span>
  499. <span class="token punctuation">&gt;</span></span>.
  500. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
  501. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
  502. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">data-name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
  503. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  504. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span></code></pre>
  505. <p>Try to hover on one of the links.</p>
  506. <astro-island uid="1sztng" prefix="r54" component-url="/_astro/HoverSync.BSxqdfai.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"HTMLAttr","value":true}' await-children=""></astro-island>
  507. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.work:has(a[data-name="book"]:hover)</span> <span class="token punctuation">{</span>
  508. <span class="token selector">img[data-name="book"]</span> <span class="token punctuation">{</span>
  509. <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1.1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  510. <span class="token punctuation">}</span>
  511. <span class="token punctuation">}</span></code></pre>
  512. <p>The possibilities are endless.</p>
  513. <h4 id="the-download-attribute">The download attribute</h4>
  514. <p>By checking for the <code>download</code> attribute in a link, we can add a download icon to indicate that. See the following:</p>
  515. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.content:has(a[download]):before</span> <span class="token punctuation">{</span>
  516. <span class="token punctuation">}</span></code></pre>
  517. <p>Here is an interactive demo. Notice how when there is a link with <code>download</code>. The design changes (Toggle the checkbox).</p>
  518. <astro-island uid="ZuN5IO" prefix="r42" component-url="/_astro/DownloadLink.4iGF9gxP.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"DownloadLink","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_6fx02_1 "><div class="_contentWrapper_6fx02_10"><div><p>Food guide.</p><p>If you are interested, your can <a href="#">Read more</a> about the guide.</p></div></div><div class="_code_6fx02_42"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">content</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain">Food guide</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain">You can </span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">#</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain">Read more</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token plain"> about the guide </span></p><p class="token-line"><span class="token plain"> .</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  519. <h4 id="reversed-list">Reversed list</h4>
  520. <p>In HTML, we can add the <code>reversed</code> attribute to a list and this will reverse the numbering. Why not add an icon if the list is revered?</p>
  521. <p>Here you go:</p>
  522. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.content:has(ol[reversed]) h3:before</span> <span class="token punctuation">{</span>
  523. <span class="token punctuation">}</span></code></pre>
  524. <astro-island uid="Z2fwxAF" prefix="r43" component-url="/_astro/ReversedList.B647vQA8.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"ReversedList","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_biq0y_1 "><div class="_contentWrapper_biq0y_10"><div><p>Upcoming confs</p><ol reversed=""><li>CSS day</li><li>Web directions summit</li><li>Smashing Conf</li></ol></div></div><div class="_code_biq0y_42"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">content</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">ol</span><span class="token tag"> </span><span class="token tag attr-name">reversed</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">ol</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  525. <h3 id="question-quiz">Question quiz</h3>
  526. <p>This is an interesting usage of CSS <code>:has()</code>. I used it for:</p>
  527. <ul>
  528. <li>Changing the header color based on whether the answer is correct or not</li>
  529. <li>If the answer is wrong, the correct one will flash in green.</li>
  530. </ul>
  531. <p>Play with the demo below:</p>
  532. <ul>
  533. <li>Pick the wrong answer (the first and last)</li>
  534. <li>Pick the correct answer (the second one)</li>
  535. </ul>
  536. <astro-island uid="2rqqiA" prefix="r44" component-url="/_astro/Question.yFB9Eue9.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"Question","value":true}' await-children=""></astro-island>
  537. <p>Here is the HTML:</p>
  538. <pre class="language-html"><code is:raw="" class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>question<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  539. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>questionHeader<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  540. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>list<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  541. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>answer<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>
  542. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span> <span class="token attr-name">data-correct</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span>
  543. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">for</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>option-0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Responsive design<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">&gt;</span></span>
  544. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  545. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  546. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span></code></pre>
  547. <p>Each option in the answers list has a <code>data-correct</code> HTML attribute. This will be useful to detect the correct answer.</p>
  548. <p>In CSS, we query the <code>.question</code> container and see if there is an answer that matches for the following:</p>
  549. <ul>
  550. <li>Checked by the user</li>
  551. <li>Has the <code>data-correct=false</code> or <code>data-correct=true</code></li>
  552. </ul>
  553. <p>If it’s false, then we add the red color.</p>
  554. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.question:has(input[data-correct="false"]:checked)</span> <span class="token punctuation">{</span>
  555. <span class="token selector">.questionHeader</span> <span class="token punctuation">{</span>
  556. <span class="token property">box-shadow</span><span class="token punctuation">:</span> inset 0 7px 0 0 <span class="token function">var</span><span class="token punctuation">(</span>--wrong<span class="token punctuation">)</span><span class="token punctuation">;</span>
  557. <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--wrong-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>
  558. <span class="token punctuation">}</span>
  559. <span class="token punctuation">}</span></code></pre>
  560. <p>And if it’s correct, the color is green.</p>
  561. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.question:has(input[data-correct="true"]:checked)</span> <span class="token punctuation">{</span>
  562. <span class="token selector">.questionHeader</span> <span class="token punctuation">{</span>
  563. <span class="token property">box-shadow</span><span class="token punctuation">:</span> inset 0 7px 0 0 <span class="token function">var</span><span class="token punctuation">(</span>--correct<span class="token punctuation">)</span><span class="token punctuation">;</span>
  564. <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--correct-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>
  565. <span class="token punctuation">}</span>
  566. <span class="token punctuation">}</span></code></pre>
  567. <p>For the flashing animation, we need to detect if an answer is wrong, and then add a CSS animation to the correct answer.</p>
  568. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.question:has(input[data-correct="false"]:checked)</span> <span class="token punctuation">{</span>
  569. <span class="token selector">input[data-correct="true"] + label</span> <span class="token punctuation">{</span>
  570. <span class="token property">animation</span><span class="token punctuation">:</span> flash 1s infinite alternate<span class="token punctuation">;</span>
  571. <span class="token punctuation">}</span>
  572. <span class="token punctuation">}</span>
  573. <span class="token atrule"><span class="token rule">@keyframes</span> flash</span> <span class="token punctuation">{</span>
  574. <span class="token selector">from</span> <span class="token punctuation">{</span>
  575. <span class="token property">background-color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
  576. <span class="token punctuation">}</span>
  577. <span class="token selector">to</span> <span class="token punctuation">{</span>
  578. <span class="token property">background-color</span><span class="token punctuation">:</span> #5ed235<span class="token punctuation">;</span>
  579. <span class="token punctuation">}</span>
  580. <span class="token punctuation">}</span></code></pre>
  581. <p>How you ever come across a use case where you need to conditionally wrap a header?</p>
  582. <p>For example, in the main landing page for non-logged users, the header is taking the full width of the viewport. For the logged user, the header’s content is within a wrapper with a maximum width.</p>
  583. <p>See the following demo and try to toggle the checkbox on and off.</p>
  584. <astro-island uid="ZK24ot" prefix="r45" component-url="/_astro/HeaderWrapper.D7ZL7RsK.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"Modal","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_6ma7f_1 undefined"><div class="_liveExample_6ma7f_92"><div><p class="_tag_6ma7f_111">HTML</p><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">header</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">#</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain">Logo</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">nav</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">nav</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></div></astro-island>
  585. <p>Notice how when there is a wrapper, the content is contained. The indicators on the left and right represent the space.</p>
  586. <p>Say we want to apply Flexbox to the header. If there is no wrapper, then flexbox is applied on the header itself. If there is a wrapper, then we apply flexbox to the wrapper.</p>
  587. <pre class="language-css"><code is:raw="" class="language-css">
  588. <span class="token selector">.siteHeader:not(:has(.headerWrapper))</span> <span class="token punctuation">{</span>
  589. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  590. <span class="token property">justify-content</span><span class="token punctuation">:</span> space-between<span class="token punctuation">;</span>
  591. <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  592. <span class="token punctuation">}</span>
  593. <span class="token selector">.siteHeader:has(.headerWrapper)</span> <span class="token punctuation">{</span>
  594. <span class="token selector">.headerWrapper</span> <span class="token punctuation">{</span>
  595. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  596. <span class="token property">justify-content</span><span class="token punctuation">:</span> space-between<span class="token punctuation">;</span>
  597. <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  598. <span class="token punctuation">}</span>
  599. <span class="token punctuation">}</span></code></pre>
  600. <p>That way, flexbox will be applied conditionally based on the presence of a wrapper.</p>
  601. <h3 id="card-thumb">Card thumb</h3>
  602. <p>A card might not always have an image. We can change the styling a bit if the card doesn’t have an image.</p>
  603. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.card:not(:has(img))</span> <span class="token punctuation">{</span>
  604. <span class="token punctuation">}</span></code></pre>
  605. <astro-island uid="Z1FdCeV" prefix="r46" component-url="/_astro/Card.BOOWbhaK.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"Card$6","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_b0aml_1"><article class="_card_b0aml_9"><img src="/assets/target-size/cookies.jpg" alt=""><div><h3>Yummy cookies</h3><p>Learn how to make great cookies at home.</p></div></article></div></div></astro-island>
  606. <h3 id="card-thumb---horizontal">Card thumb - horizontal</h3>
  607. <p>Or we might need to change the card to a horizontal style if there is an image.</p>
  608. <astro-island uid="Z14dyoF" prefix="r47" component-url="/_astro/Card2.COhyOo_1.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"Card$5","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_17s0l_1"><div class="_code_17s0l_82"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">article</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">card</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">h3</span><span class="token tag punctuation">&gt;</span><span class="token plain">Yummy cookies</span><span class="token tag punctuation">&lt;/</span><span class="token tag">h3</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain">Learn how to make great cookies at home.</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">article</span><span class="token tag punctuation">&gt;</span></p></pre></div><div><article class="_card_17s0l_12"><div><h3>Yummy cookies</h3><p>Learn how to make great cookies at home.</p></div></article></div></div></div></astro-island>
  609. <p>In the following example, we have a navigation. When one of the <code>&lt;li&gt;</code> items have a secondary menu, we want to use <code>:has()</code> to add an arrow to the <code>&lt;li&gt;</code>.</p>
  610. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">li:has(.subMenu)</span> <span class="token punctuation">{</span>
  611. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  612. <span class="token property">justify-content</span><span class="token punctuation">:</span> space-between<span class="token punctuation">;</span>
  613. <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  614. <span class="token punctuation">}</span>
  615. <span class="token selector">li:has(.subMenu) a:after</span> <span class="token punctuation">{</span>
  616. <span class="token punctuation">}</span></code></pre>
  617. <astro-island uid="1Mc51N" prefix="r48" component-url="/_astro/Card3.1qk2myZs.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"Card$4","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_1rewo_1"><div class="_code_1rewo_91"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">ul</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">nav</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">/products</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain">Products</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">ul</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  618. <p>Based on the previous example, say we have a submenu with a dynamic number of items. We can change the menu grid based on the number of items.</p>
  619. <p>Play with the add and remove buttons in the demo to see it yourself.</p>
  620. <astro-island uid="2sKa5H" prefix="r49" component-url="/_astro/MenuGrid.DvuMzUJl.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"MenuGrid","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_1vpko_1"><p class="demoActions"><button class="button button--add">Add</button><button class="button button-remove">Remove</button><button class="button button--reset">Reset</button></p><div class="_code_1vpko_98"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">ul</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">nav</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">/products</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain">Products</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">ul</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">subMenu</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">#</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain">Item 1</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">#</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain">Item 2</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">#</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain">Item 3</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">#</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain">Item 4</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">#</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain">Item 5</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">ul</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">li</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">ul</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  621. <p>This is done via the <code>:nth-last-child</code></p>
  622. <pre class="language-css"><code is:raw="" class="language-css">
  623. <span class="token selector">.submenu:has(li:nth-last-child(n + 6))</span> <span class="token punctuation">{</span>
  624. <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  625. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr 1fr<span class="token punctuation">;</span>
  626. <span class="token property">width</span><span class="token punctuation">:</span> 250px<span class="token punctuation">;</span>
  627. <span class="token punctuation">}</span>
  628. <span class="token selector">.submenu:has(li:nth-last-child(n + 8))</span> <span class="token punctuation">{</span>
  629. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr 1fr 1fr<span class="token punctuation">;</span>
  630. <span class="token property">width</span><span class="token punctuation">:</span> 350px<span class="token punctuation">;</span>
  631. <span class="token punctuation">}</span></code></pre>
  632. <h3 id="articles-section">Articles section</h3>
  633. <p>This example is inspired from Jen Simmons CSS <code>:has()</code> <a href="https://webkit.org/blog/13096/css-has-pseudo-class/">article on webkit</a>. The idea is to change the CSS grid if an article contain an image.</p>
  634. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.grid</span> <span class="token punctuation">{</span>
  635. <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  636. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr 1fr 1fr<span class="token punctuation">;</span>
  637. <span class="token property">gap</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  638. <span class="token punctuation">}</span>
  639. <span class="token selector">.article:has(img)</span> <span class="token punctuation">{</span>
  640. <span class="token property">grid-column</span><span class="token punctuation">:</span> span 2<span class="token punctuation">;</span>
  641. <span class="token property">grid-row</span><span class="token punctuation">:</span> span 2<span class="token punctuation">;</span>
  642. <span class="token punctuation">}</span></code></pre>
  643. <p>Play with the demo below:</p>
  644. <astro-island uid="zWfxI" prefix="r50" component-url="/_astro/Card4.CuvLGsMb.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"Card$3","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_it94y_1"><div><div class="_grid_it94y_12"><article class="_article_it94y_18"><p>Fruit Tart Mastery</p><p>Perfecting the art of fruity tart creation.</p></article><article class="_article_it94y_18"><p>Ultimate Brownie Bliss</p><p>Elevate your baking with irresistible brownies</p></article><article class="_article_it94y_18"><p>Fruit Tart Mastery</p><p>Unlock the secrets to perfect Focaccia baking.</p></article></div></div><div class="_code_it94y_42"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">grid</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">article</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain">Fruit Tart Mastery</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain">Perfecting the art of fruity tart creation.</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">article</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">article</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">article</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  645. <p>We can take that further and make a lot of variations. For example, I want to style the grid differently if:</p>
  646. <ul>
  647. <li>There is a grid with two items</li>
  648. <li>Both items have photos</li>
  649. </ul>
  650. <h3 id="hero-section">Hero section</h3>
  651. <p>In this example, we have a hero section. When there is no image, the content should be centered. When there is an image, it will display both text and image next to each other.</p>
  652. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.hero</span> <span class="token punctuation">{</span>
  653. <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  654. <span class="token punctuation">}</span>
  655. <span class="token selector">.hero:has(img)</span> <span class="token punctuation">{</span>
  656. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 2fr 1fr<span class="token punctuation">;</span>
  657. <span class="token property">text-align</span><span class="token punctuation">:</span> start<span class="token punctuation">;</span>
  658. <span class="token punctuation">}</span></code></pre>
  659. <astro-island uid="1DTD2M" prefix="r51" component-url="/_astro/Card5.BnAtjreY.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"Card$2","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_u1612_1"><div><section class="_testSection_u1612_12"><div><h3>Fruit tart.</h3><p>Learn how to make the best tart.</p></div></section></div><div class="_code_u1612_32"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">section</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">sectionContent</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">sectionThumb</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">section</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  660. <h3 id="card-actions">Card actions</h3>
  661. <p>In this demo, we have a card with two possible states for the actions:</p>
  662. <ul>
  663. <li>One link “view recipe”</li>
  664. <li>Multiple actions: “Like, share, context menu”</li>
  665. </ul>
  666. <p>We can use CSS <code>:has()</code> to check if <strong>one of the start or end</strong> elements is there and change the UI accordingly.</p>
  667. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.card:not(:has(img))</span> <span class="token punctuation">{</span>
  668. <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in srgb<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand-1<span class="token punctuation">)</span><span class="token punctuation">,</span> #fff 95%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  669. <span class="token property">border-left</span><span class="token punctuation">:</span> 4px solid <span class="token function">var</span><span class="token punctuation">(</span>--brand-1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  670. <span class="token property">max-width</span><span class="token punctuation">:</span> 250px<span class="token punctuation">;</span>
  671. <span class="token punctuation">}</span>
  672. <span class="token selector">.cardActions:has(.start, .end)</span> <span class="token punctuation">{</span>
  673. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  674. <span class="token property">justify-content</span><span class="token punctuation">:</span> space-between<span class="token punctuation">;</span>
  675. <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  676. <span class="token punctuation">}</span></code></pre>
  677. <p>See the demo below:</p>
  678. <astro-island uid="ZDx3wA" prefix="r52" component-url="/_astro/CardActions.CmCbdIia.js" component-export="default" renderer-url="/_astro/client.C9CDoPFW.js" props="{}" ssr="" client="visible" opts='{"name":"Card$1","value":true}' await-children=""><div><div class="example-wrapper center _wrapper_3npq_1"><div class="_cardContainer_3npq_12"><article class="_card_3npq_12"><img src="/assets/css-has-guide/tart.jpeg" alt=""><div><h3>Fruit tart</h3><p class="_desc_3npq_53">Learn how to make great cookies at home.</p></div></article></div><div class="_code_3npq_88"><pre class="prism-code language-html"><p class="token-line"><span class="token tag punctuation">&lt;</span><span class="token tag">article</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">card</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">img</span><span class="token tag"> </span><span class="token tag attr-name">src</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">thumb.jpg</span><span class="token tag attr-value punctuation">"</span><span class="token tag"> </span><span class="token tag attr-name">alt</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value punctuation">"</span><span class="token tag"> </span><span class="token tag punctuation">/&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">content</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag"> </span><span class="token tag attr-name">class</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">cardActions</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span></p><p class="token-line"></p><p class="token-line"></p><p class="token-line"></p><p class="token-line"></p><p class="token-line"></p><p class="token-line"><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;</span><span class="token tag">a</span><span class="token tag"> </span><span class="token tag attr-name">href</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">"</span><span class="token tag attr-value">#</span><span class="token tag attr-value punctuation">"</span><span class="token tag punctuation">&gt;</span><span class="token plain">View recipe</span><span class="token tag punctuation">&lt;/</span><span class="token tag">a</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"> </span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></p><p class="token-line"><span class="token plain"></span><span class="token tag punctuation">&lt;/</span><span class="token tag">article</span><span class="token tag punctuation">&gt;</span></p></pre></div></div></div></astro-island>
  679. <h2 id="outro">Outro</h2>
  680. <p>CSS <code>:has()</code> is a powerful feature that opens a lot of possibilities that weren’t possible before. It literally gives us CSS superpowers! I recommend you start using it today and experiment with it.</p>
  681. <h2 id="resources">Resources</h2>
  682. <div class="coffee-support"> <p>
  683. Enjoyed the read? If you'd like to support my work,
  684. consider buying me a coffee. <strong>This interactive guide took a month, which translates
  685. to 30 coffee cups.</strong> Thanks a latte!
  686. </p> <a href="https://ko-fi.com/ahmadshadeed" target="_blank"><img src="/assets/kofi_button_stroke.png" alt="Support me on Ko-fi" loading="lazy" decoding="async"></a> </div> <section class="newsletter"> <div> <h2>Subscribe to my newsletter</h2> <p>
  687. A place where I share all the awesome CSS articles,
  688. demos, and updates that I like.
  689. </p> </div> </section> </div>