A place to cache linked articles (think custom and personal wayback machine)
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

index.md 148KB

8 månader sedan
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>