A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.html 156KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="en">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>CSS :has() Interactive Guide (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f7f7f7">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
  26. <meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
  27. <!-- Is that even respected? Retrospectively? What a shAItshow…
  28. https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
  29. <meta name="robots" content="noai, noimageai">
  30. <!-- Documented, feel free to shoot an email. -->
  31. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  32. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  35. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  36. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  37. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  38. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  39. <script>
  40. function toggleTheme(themeName) {
  41. document.documentElement.classList.toggle(
  42. 'forced-dark',
  43. themeName === 'dark'
  44. )
  45. document.documentElement.classList.toggle(
  46. 'forced-light',
  47. themeName === 'light'
  48. )
  49. }
  50. const selectedTheme = localStorage.getItem('theme')
  51. if (selectedTheme !== 'undefined') {
  52. toggleTheme(selectedTheme)
  53. }
  54. </script>
  55. <meta name="robots" content="noindex, nofollow">
  56. <meta content="origin-when-cross-origin" name="referrer">
  57. <!-- Canonical URL for SEO purposes -->
  58. <link rel="canonical" href="https://ishadeed.com/article/css-has-guide/">
  59. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  60. <article>
  61. <header>
  62. <h1>CSS :has() Interactive Guide</h1>
  63. </header>
  64. <nav>
  65. <p class="center">
  66. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  67. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  68. </svg> Accueil</a> •
  69. <a href="https://ishadeed.com/article/css-has-guide/" title="Lien vers le contenu original">Source originale</a>
  70. <br>
  71. Mis en cache le 2024-03-07
  72. </p>
  73. </nav>
  74. <hr>
  75. <div class="post-content prose"> <h2 id="intro">Intro</h2>
  76. <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>
  77. <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>
  78. <h3 id="the-problem">The problem</h3>
  79. <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>
  80. <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>
  81. <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>
  82. <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>
  83. <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>
  84. <p>See the following demo. Try to toggle the “Show caption”.</p>
  85. <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>
  86. <p>When there is a caption, I want the figure to have the following:</p>
  87. <ul>
  88. <li>Padding</li>
  89. <li>Background</li>
  90. <li>Shadow</li>
  91. </ul>
  92. <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>
  93. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">figure.with-caption</span> <span class="token punctuation">{</span>
  94. <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  95. <span class="token property">background-color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  96. <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>
  97. <span class="token property">border-radius</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
  98. <span class="token punctuation">}</span></code></pre>
  99. <p>This is not doable when we have generated HTML content (e.g: an article body).</p>
  100. <h3 id="the-solution">The solution</h3>
  101. <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>
  102. <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>
  103. <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>
  104. <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>
  105. <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  106. <span class="token property">background-color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  107. <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>
  108. <span class="token property">border-radius</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
  109. <span class="token punctuation">}</span></code></pre></details>
  110. <p>In the following demo, notice how when the <code>&lt;figcaption&gt;</code> is commented, the CSS <code>:has()</code> takes action.</p>
  111. <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>
  112. <p>This is just scratching the surface of problems we can solve with CSS <code>:has()</code>.</p>
  113. <h2 id="css-selectors-recap">CSS selectors recap</h2>
  114. <p>Before diving into some interesting CSS selectors with <code>:has()</code>, let’s do a quick recap on them.</p>
  115. <h3 id="adjacent-sibling-selector">Adjacent sibling selector</h3>
  116. <p>To select the next sibling of an element, we can use the adjacent sibling selector (+) for that.</p>
  117. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.book</span> <span class="token punctuation">{</span>
  118. <span class="token property">opacity</span><span class="token punctuation">:</span> 0.2<span class="token punctuation">;</span>
  119. <span class="token punctuation">}</span>
  120. <span class="token selector">.frame + .book</span> <span class="token punctuation">{</span>
  121. <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
  122. <span class="token punctuation">}</span></code></pre>
  123. <p>Try it yourself in the demo below.</p>
  124. <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>
  125. <h3 id="general-sibling-selector">General sibling selector</h3>
  126. <p>To select all the next siblings of an element, we can use the general sibling selector (~) for that.</p>
  127. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.book</span> <span class="token punctuation">{</span>
  128. <span class="token property">opacity</span><span class="token punctuation">:</span> 0.2<span class="token punctuation">;</span>
  129. <span class="token punctuation">}</span>
  130. <span class="token selector">.frame ~ .book</span> <span class="token punctuation">{</span>
  131. <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
  132. <span class="token punctuation">}</span></code></pre>
  133. <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>
  134. <h3 id="the-previous-sibling-selector">The previous sibling selector</h3>
  135. <p>With CSS <code>:has()</code>, we can take the above further and select the previous sibling of an element.</p>
  136. <p>In the following snippet, the <code>:has()</code> makes it possible to select a book that is followed by a frame.</p>
  137. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.book</span> <span class="token punctuation">{</span>
  138. <span class="token property">opacity</span><span class="token punctuation">:</span> 0.2<span class="token punctuation">;</span>
  139. <span class="token punctuation">}</span>
  140. <span class="token selector">.book:has(+ .frame)</span> <span class="token punctuation">{</span>
  141. <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
  142. <span class="token punctuation">}</span></code></pre>
  143. <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>
  144. <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>
  145. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.book</span> <span class="token punctuation">{</span>
  146. <span class="token property">opacity</span><span class="token punctuation">:</span> 0.2<span class="token punctuation">;</span>
  147. <span class="token punctuation">}</span>
  148. <span class="token selector">.book:has(~ .frame)</span> <span class="token punctuation">{</span>
  149. <span class="token property">opacity</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
  150. <span class="token punctuation">}</span></code></pre>
  151. <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>
  152. <h3 id="the-child-combinator">The child combinator</h3>
  153. <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>
  154. <p>Review your knowledge with the demo below.</p>
  155. <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>
  156. <h3 id="the-not-pseudo-class">The :not pseudo-class</h3>
  157. <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>
  158. <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>
  159. <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>
  160. <h2 id="css-has-selectors-matching">CSS :has() selectors matching</h2>
  161. <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>
  162. <p>The following are general examples for you to practise.</p>
  163. <h3 id="card-with-image">Card with image</h3>
  164. <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>
  165. <p>Try to toggle the checkbox and see how the CSS selector works only when there is an image.</p>
  166. <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>
  167. <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>
  168. <p>Try it yourself.</p>
  169. <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>
  170. <h3 id="card-without-an-image">Card without an image</h3>
  171. <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>
  172. <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>
  173. <h3 id="adjacent-sibling-and-has">Adjacent sibling and :has</h3>
  174. <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>
  175. <p>By default, the frame comes after the book. Toggle the checkbox and see how the CSS <code>:has()</code> selector will work.</p>
  176. <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>
  177. <h3 id="select-a-shelf-if-it-only-contains-a-box">Select a shelf if it only contains a box</h3>
  178. <p>In this example, the CSS <code>:has()</code> selector tries to match if there are books inside the box container only.</p>
  179. <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>
  180. <h3 id="select-a-box-without-a-blue-book">Select a box without a blue book</h3>
  181. <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>
  182. <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>
  183. <h3 id="select-the-box-with-3-books">Select the box with 3+ books</h3>
  184. <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>
  185. <h3 id="change-the-book-order-based-on-the-number">Change the book order based on the number</h3>
  186. <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>
  187. <p>Try to add more books and see what happens.</p>
  188. <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>
  189. <p>By using the <code>:nth-last-child()</code>, this is possible.</p>
  190. <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>
  191. <span class="token property">flex-direction</span><span class="token punctuation">:</span> row<span class="token punctuation">;</span>
  192. <span class="token selector">.book</span> <span class="token punctuation">{</span>
  193. <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
  194. <span class="token property">width</span><span class="token punctuation">:</span> 22px<span class="token punctuation">;</span>
  195. <span class="token punctuation">}</span>
  196. <span class="token punctuation">}</span></code></pre>
  197. <h3 id="add-spacing-to-each-3rd-items-if-5-books">Add spacing to each 3rd items if 5+ books</h3>
  198. <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>
  199. <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>
  200. <h3 id="the-bookshelf">The bookshelf</h3>
  201. <p>A fun example where I have the following conditions with CSS <code>:has()</code>:</p>
  202. <ul>
  203. <li>Change the books from stack to stand based on their number</li>
  204. <li>Hang the frame to the wall if certain number of books is there</li>
  205. <li>Throw the plant and earth on the ground</li>
  206. </ul>
  207. <p>Play with the demo.</p>
  208. <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>
  209. <h4 id="change-books-ordering">Change books ordering</h4>
  210. <p>The first thing is that I want to change the books from stack to stand, if there are 5+ books.</p>
  211. <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>
  212. <span class="token property">flex-direction</span><span class="token punctuation">:</span> row<span class="token punctuation">;</span>
  213. <span class="token selector">.book</span> <span class="token punctuation">{</span>
  214. <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
  215. <span class="token property">width</span><span class="token punctuation">:</span> 22px<span class="token punctuation">;</span>
  216. <span class="token punctuation">}</span>
  217. <span class="token punctuation">}</span></code></pre>
  218. <h4 id="hang-the-frame-to-the-wall">Hang the frame to the wall</h4>
  219. <p>If there 6+ books, the frame should be moved to the wall.</p>
  220. <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>
  221. <span class="token selector">.frame</span> <span class="token punctuation">{</span>
  222. <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
  223. <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>
  224. <span class="token property">top</span><span class="token punctuation">:</span> -165%<span class="token punctuation">;</span>
  225. <span class="token punctuation">}</span>
  226. <span class="token punctuation">}</span></code></pre>
  227. <h4 id="throw-the-plant-and-earth">Throw the plant and earth</h4>
  228. <p>No space at all? Simple, throw the plant and earth to the ground, but I’m not responsible for any mess.</p>
  229. <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>
  230. <span class="token selector">.plant</span> <span class="token punctuation">{</span>
  231. <span class="token property">animation</span><span class="token punctuation">:</span> movePlant 0.6s forwards<span class="token punctuation">;</span>
  232. <span class="token punctuation">}</span>
  233. <span class="token selector">.earth</span> <span class="token punctuation">{</span>
  234. <span class="token property">animation</span><span class="token punctuation">:</span> moveEarth 0.6s forwards<span class="token punctuation">;</span>
  235. <span class="token punctuation">}</span>
  236. <span class="token punctuation">}</span></code></pre>
  237. <h3 id="logical-operators-with-css-has">Logical operators with CSS :has</h3>
  238. <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>
  239. <ul>
  240. <li>Select the shelf if it contains the purple <strong>and</strong> yellow book.</li>
  241. <li>Select the shelf if it contains the purple <strong>or</strong> the yellow book.</li>
  242. </ul>
  243. <p>Try the following:</p>
  244. <ul>
  245. <li>Toggle the books on or off</li>
  246. <li>Change the option in the menu between “and” / “or”</li>
  247. </ul>
  248. <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>
  249. <p>In CSS, here is what’s happening:</p>
  250. <pre class="language-css"><code is:raw="" class="language-css">
  251. <span class="token selector">.shelf:has(.bookPurple, .bookYellow)</span> <span class="token punctuation">{</span>
  252. <span class="token property">outline</span><span class="token punctuation">:</span> dashed 2px deeppink<span class="token punctuation">;</span>
  253. <span class="token punctuation">}</span>
  254. <span class="token selector">.shelf:has(.bookPurple):has(.bookYellow)</span> <span class="token punctuation">{</span>
  255. <span class="token property">outline</span><span class="token punctuation">:</span> dashed 2px deeppink<span class="token punctuation">;</span>
  256. <span class="token punctuation">}</span></code></pre>
  257. <p>It’s amazing what we can do with logical operators in CSS <code>:has()</code>.</p>
  258. <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>
  259. <h2 id="use-cases-for-css-has">Use cases for CSS :has</h2>
  260. <h3 id="file-download">File download</h3>
  261. <p>This is one of my favorite use cases in this article. Say we have a file component that shows the following:</p>
  262. <ul>
  263. <li>File image</li>
  264. <li>Name</li>
  265. <li>Meta info (pages, size, etc)</li>
  266. </ul>
  267. <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>
  268. <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>
  269. <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">;</span>
  270. <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>
  271. <span class="token punctuation">}</span>
  272. <span class="token selector">.file:has([href$=".pdf"])</span> <span class="token punctuation">{</span>
  273. <span class="token property">--bg</span><span class="token punctuation">:</span> <span class="token string">"icon-pdf.png"</span><span class="token punctuation">;</span>
  274. <span class="token punctuation">}</span>
  275. </code></pre>
  276. <p>Try to toggle the image, then change the file type and see what happens. This is magic, isn’t it?</p>
  277. <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>
  278. <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>
  279. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.layout</span> <span class="token punctuation">{</span>
  280. <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  281. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> max-content 1fr<span class="token punctuation">;</span>
  282. <span class="token punctuation">}</span>
  283. <span class="token selector">.sidebar:has(.widget)</span> <span class="token punctuation">{</span>
  284. <span class="token property">width</span><span class="token punctuation">:</span> 180px<span class="token punctuation">;</span>
  285. <span class="token punctuation">}</span></code></pre>
  286. <p>Try it in the interactive demo. I recommend to view this on a large screen.</p>
  287. <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>
  288. <h3 id="cookies-banner">Cookies Banner</h3>
  289. <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>
  290. <p>Toggle the banner in the demo below. Notice how the widget is hidden under the banner. This isn’t good.</p>
  291. <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>
  292. <p>We can use CSS <code>:has()</code> to move the widget <strong>if the banner is shown</strong>.</p>
  293. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">body:has(.banner) .fab</span> <span class="token punctuation">{</span>
  294. <span class="token property">bottom</span><span class="token punctuation">:</span> 6rem<span class="token punctuation">;</span>
  295. <span class="token punctuation">}</span></code></pre>
  296. <p>Play with the demo and toggle the CSS <code>:has()</code> checkbox.</p>
  297. <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>
  298. <h3 id="dashboard-banner">Dashboard banner</h3>
  299. <p>In this example, I want to show an additional visual clue if the page has an alert.</p>
  300. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.main:has(.alert) .header</span> <span class="token punctuation">{</span>
  301. <span class="token property">box-shadow</span><span class="token punctuation">:</span>
  302. inset 0 2px 0 0 red<span class="token punctuation">,</span>
  303. 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>
  304. <span class="token property">background-color</span><span class="token punctuation">:</span> #fff4f4<span class="token punctuation">;</span>
  305. <span class="token punctuation">}</span></code></pre>
  306. <p>Toggle the alert and what happens.</p>
  307. <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>
  308. <h3 id="quantity-queries-with-css-has">Quantity queries with CSS :has</h3>
  309. <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>
  310. <p>The idea is to use the CSS <code>:nth-last-child</code> like this:</p>
  311. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">li:nth-last-child(n + 5),
  312. li:nth-last-child(n + 5) ~ li</span> <span class="token punctuation">{</span>
  313. <span class="token property">width</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span>
  314. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  315. <span class="token property">flex-direciton</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span>
  316. <span class="token punctuation">}</span></code></pre>
  317. <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>
  318. <p>With CSS <code>:has()</code>, this is possible.</p>
  319. <p>Here is an example:</p>
  320. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.wrapper</span> <span class="token punctuation">{</span>
  321. <span class="token property">--item-size</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span>
  322. <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  323. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>
  324. auto-fit<span class="token punctuation">,</span>
  325. <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>
  326. <span class="token punctuation">)</span><span class="token punctuation">;</span>
  327. <span class="token property">gap</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  328. <span class="token punctuation">}</span>
  329. <span class="token selector">.wrapper:has(li:nth-last-child(n + 5))</span> <span class="token punctuation">{</span>
  330. <span class="token property">--item-size</span><span class="token punctuation">:</span> 200px<span class="token punctuation">;</span>
  331. <span class="token punctuation">}</span></code></pre>
  332. <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>
  333. <p>See the interactive demo below. Here is what’s happening:</p>
  334. <ul>
  335. <li>There is a quantity query with CSS <code>:has()</code>. I have 3 of them.</li>
  336. <li>When the number of items changes, the matching query will work.</li>
  337. </ul>
  338. <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>
  339. <h3 id="select-title-that-comes-after-a-link">Select title that comes after a link</h3>
  340. <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>
  341. <p>Without CSS <code>:has()</code>, we’re limited to the following only:</p>
  342. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.prose a + h3</span> <span class="token punctuation">{</span>
  343. <span class="token punctuation">}</span></code></pre>
  344. <p>With CSS <code>:has()</code>, we can straightforwardly do that.</p>
  345. <pre class="language-css"><code is:raw="" class="language-css">
  346. <span class="token selector">a:has(+ h3)</span> <span class="token punctuation">{</span>
  347. <span class="token property">display</span><span class="token punctuation">:</span> inline-flex<span class="token punctuation">;</span>
  348. <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>
  349. <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  350. <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem 1rem<span class="token punctuation">;</span>
  351. <span class="token property">border-radius</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
  352. <span class="token punctuation">}</span></code></pre>
  353. <p>Play with the interactive demo below.</p>
  354. <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>
  355. <h3 id="card-with-a-disabled-button">Card with a disabled button</h3>
  356. <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>
  357. <p>We can hide the “add to cart” button, or show a “Notify me when available”. Whatever works best for your case.</p>
  358. <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>
  359. <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
  360. <span class="token punctuation">}</span></code></pre>
  361. <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>
  362. <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>
  363. <pre class="language-scss"><code is:raw="" class="language-scss"><span class="token selector">.card </span><span class="token punctuation">{</span>
  364. &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>
  365. <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span>
  366. <span class="token selector"><span class="token parent important">&amp;</span>:after </span><span class="token punctuation">{</span>
  367. <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">"Not available"</span><span class="token punctuation">;</span>
  368. <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
  369. <span class="token property">inset-inline</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
  370. <span class="token property">top</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
  371. <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  372. <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>
  373. <span class="token punctuation">}</span>
  374. <span class="token punctuation">}</span>
  375. <span class="token punctuation">}</span></code></pre>
  376. <p>Try to toggle “out of stock” and see what happens.</p>
  377. <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>
  378. <h3 id="card-with-hovered-button">Card with hovered button</h3>
  379. <p>We can add a hover effect to a card if a button is hovered.</p>
  380. <p>Try to hover on the button and see how the card shadow changes. This is all with CSS <code>:has()</code>.</p>
  381. <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>
  382. <p>For me, this is like <code>:focus-within</code>. Maybe I should call it <code>:hover-within</code>?</p>
  383. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.card:has(.button:hover)</span> <span class="token punctuation">{</span>
  384. <span class="token property">box-shadow</span><span class="token punctuation">:</span>
  385. 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>
  386. 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>
  387. <span class="token punctuation">}</span></code></pre>
  388. <p>Toggle the 2nd style and see a different styling option. This is all done with CSS <code>:has()</code>.</p>
  389. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  390. <span class="token selector">&amp;:has(.button:hover)</span> <span class="token punctuation">{</span>
  391. <span class="token property">color</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  392. <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>
  393. <span class="token property">box-shadow</span><span class="token punctuation">:</span>
  394. 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>
  395. 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>
  396. 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>
  397. <span class="token selector">.button</span> <span class="token punctuation">{</span>
  398. <span class="token property">color</span><span class="token punctuation">:</span> inherit<span class="token punctuation">;</span>
  399. <span class="token punctuation">}</span>
  400. <span class="token selector">h3,
  401. p</span> <span class="token punctuation">{</span>
  402. <span class="token property">color</span><span class="token punctuation">:</span> inherit<span class="token punctuation">;</span>
  403. <span class="token punctuation">}</span>
  404. <span class="token punctuation">}</span>
  405. <span class="token punctuation">}</span></code></pre>
  406. <h3 id="modal">Modal</h3>
  407. <p>In a modal, we might need to change the title color if it’s about a critical action, like deleting something important.</p>
  408. <p>See the following demo. We have a modal with action buttons.</p>
  409. <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>
  410. <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>
  411. <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>
  412. <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>
  413. <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>
  414. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  415. <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>
  416. <p>And then style it like so:</p>
  417. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.modal--danger h2</span> <span class="token punctuation">{</span>
  418. <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
  419. <span class="token punctuation">}</span></code></pre>
  420. <p>With CSS <code>:has()</code>, all we need to do is the following:</p>
  421. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.modal</span> <span class="token punctuation">{</span>
  422. <span class="token selector">&amp;:has(.btn--danger)</span> <span class="token punctuation">{</span>
  423. <span class="token selector">.modal-title</span> <span class="token punctuation">{</span>
  424. <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
  425. <span class="token punctuation">}</span>
  426. <span class="token punctuation">}</span>
  427. <span class="token punctuation">}</span></code></pre>
  428. <p>See the interactive demo.</p>
  429. <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>
  430. <h3 id="modal-buttons">Modal buttons</h3>
  431. <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>
  432. <p>Try to toggle the checkbox and see what happens.</p>
  433. <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>
  434. <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>
  435. <p>See the following HTML.</p>
  436. <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>
  437. <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>
  438. <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>
  439. <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>
  440. <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>
  441. <p>In CSS, we need to check if the number of buttons is three. If yes:</p>
  442. <ul>
  443. <li>position the last one on the far right</li>
  444. <li>change <code>justify-content</code> to <code>stretch</code></li>
  445. </ul>
  446. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.modal-actions</span> <span class="token punctuation">{</span>
  447. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  448. <span class="token property">justify-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  449. <span class="token property">gap</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  450. <span class="token selector">&amp;:has(.btn:nth-last-child(n + 3))</span> <span class="token punctuation">{</span>
  451. <span class="token property">justify-content</span><span class="token punctuation">:</span> stretch<span class="token punctuation">;</span>
  452. <span class="token selector">.btn:last-child</span> <span class="token punctuation">{</span>
  453. <span class="token property">margin-inline-start</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
  454. <span class="token punctuation">}</span>
  455. <span class="token punctuation">}</span>
  456. <span class="token punctuation">}</span></code></pre>
  457. <p>We can even go further and make more styling changes. For example:</p>
  458. <ul>
  459. <li>Change the background color</li>
  460. <li>Add a border</li>
  461. <li>Add padding</li>
  462. <li>Reset paddings with negative margins (kind of a hack)</li>
  463. </ul>
  464. <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>
  465. <p>Here is the CSS:</p>
  466. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.modal-actions</span> <span class="token punctuation">{</span>
  467. <span class="token selector">&amp;:has(.btn:nth-last-child(n + 3))</span> <span class="token punctuation">{</span>
  468. <span class="token property">justify-content</span><span class="token punctuation">:</span> stretch<span class="token punctuation">;</span>
  469. <span class="token property">border-top</span><span class="token punctuation">:</span> 1px solid #d3d3d3<span class="token punctuation">;</span>
  470. <span class="token property">background-color</span><span class="token punctuation">:</span> #f5f5f5<span class="token punctuation">;</span>
  471. <span class="token property">padding</span><span class="token punctuation">:</span> 0.75rem<span class="token punctuation">;</span>
  472. <span class="token property">margin-inline</span><span class="token punctuation">:</span> -1rem<span class="token punctuation">;</span>
  473. <span class="token property">margin-bottom</span><span class="token punctuation">:</span> -1rem<span class="token punctuation">;</span>
  474. <span class="token selector">.btn:last-child</span> <span class="token punctuation">{</span>
  475. <span class="token property">margin-inline-start</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
  476. <span class="token punctuation">}</span>
  477. <span class="token punctuation">}</span>
  478. <span class="token punctuation">}</span></code></pre>
  479. <h3 id="section-empty-state">Section empty state</h3>
  480. <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>
  481. <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>
  482. <p>Here is the section with the content.</p>
  483. <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>
  484. <p>When there is no content, it should look like this:</p>
  485. <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>
  486. <p>We can check the <code>:empty</code> pseudo-class on the parent and do the styles we need.</p>
  487. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.section:has(.sectionContent:empty)</span> <span class="token punctuation">{</span>
  488. <span class="token punctuation">}</span></code></pre>
  489. <p>Here is the complete CSS:</p>
  490. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.section:has(.sectionContent:empty)</span> <span class="token punctuation">{</span>
  491. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  492. <span class="token property">flex-direction</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span>
  493. <span class="token property">justify-content</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  494. <span class="token property">min-height</span><span class="token punctuation">:</span> 150px<span class="token punctuation">;</span>
  495. <span class="token selector">.sectionHeader</span> <span class="token punctuation">{</span>
  496. <span class="token selector">p:first-child</span> <span class="token punctuation">{</span>
  497. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  498. <span class="token property">flex-direction</span><span class="token punctuation">:</span> column<span class="token punctuation">;</span>
  499. <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  500. <span class="token property">gap</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  501. <span class="token selector">&amp;:before</span> <span class="token punctuation">{</span>
  502. <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">;</span>
  503. <span class="token property">--size</span><span class="token punctuation">:</span> 3rem<span class="token punctuation">;</span>
  504. <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span>
  505. <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>
  506. <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>
  507. <span class="token property">background-color</span><span class="token punctuation">:</span> lightblue<span class="token punctuation">;</span>
  508. <span class="token property">border-radius</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span>
  509. <span class="token punctuation">}</span>
  510. <span class="token punctuation">}</span>
  511. <span class="token selector">p:last-child</span> <span class="token punctuation">{</span>
  512. <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span>
  513. <span class="token punctuation">}</span>
  514. <span class="token punctuation">}</span>
  515. <span class="token punctuation">}</span></code></pre>
  516. <p>Play with the demo below.</p>
  517. <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>
  518. <h3 id="input-states">Input states</h3>
  519. <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>
  520. <h4 id="checkbox-and-css-has">Checkbox and CSS :has</h4>
  521. <p>We can check the value of a checkbox and do something as a result of it. See the following demo:</p>
  522. <p>If the checkbox is checked, the button will be enabled.</p>
  523. <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>
  524. <p>It’s like an if statement in Javascript, or a React state. Interesting, right?</p>
  525. <h4 id="radio-button-and-css-has">Radio button and CSS :has</h4>
  526. <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>
  527. <p>See the following demo:</p>
  528. <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>
  529. <h3 id="select-menu-and-css-has">Select menu and CSS :has</h3>
  530. <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>
  531. <p>For example, if the user selects “other”, we want to show input to let them fill in more info.</p>
  532. <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>
  533. <h3 id="html-attributes">HTML attributes</h3>
  534. <h4 id="disabled-attribute">Disabled attribute</h4>
  535. <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>
  536. <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>
  537. <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>
  538. <h4 id="dual-hover-with-data-attributes-and-has">Dual hover with data attributes and :has</h4>
  539. <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>
  540. <p>I first saw this by <a href="https://twitter.com/pomber/status/1739617079404134821">Rodrigo Pombo</a> and I was like 😱.</p>
  541. <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>
  542. <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>
  543. <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>
  544. <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>
  545. <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>
  546. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
  547. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
  548. <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>
  549. <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>
  550. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  551. <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>
  552. <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>
  553. <span class="token property">outline</span><span class="token punctuation">:</span> 2px solid<span class="token punctuation">;</span>
  554. <span class="token punctuation">}</span></code></pre>
  555. <p>See the following demo:</p>
  556. <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>
  557. <h4 id="dual-hover-example">Dual hover example</h4>
  558. <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>
  559. <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>
  560. <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>
  561. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>
  562. I wrote a book on
  563. <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>
  564. Debugging CSS <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span>
  565. <span class="token punctuation">&gt;</span></span>.
  566. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
  567. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
  568. <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>
  569. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  570. <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>
  571. <p>Try to hover on one of the links.</p>
  572. <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>
  573. <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>
  574. <span class="token selector">img[data-name="book"]</span> <span class="token punctuation">{</span>
  575. <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>
  576. <span class="token punctuation">}</span>
  577. <span class="token punctuation">}</span></code></pre>
  578. <p>The possibilities are endless.</p>
  579. <h4 id="the-download-attribute">The download attribute</h4>
  580. <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>
  581. <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>
  582. <span class="token punctuation">}</span></code></pre>
  583. <p>Here is an interactive demo. Notice how when there is a link with <code>download</code>. The design changes (Toggle the checkbox).</p>
  584. <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>
  585. <h4 id="reversed-list">Reversed list</h4>
  586. <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>
  587. <p>Here you go:</p>
  588. <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>
  589. <span class="token punctuation">}</span></code></pre>
  590. <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>
  591. <h3 id="question-quiz">Question quiz</h3>
  592. <p>This is an interesting usage of CSS <code>:has()</code>. I used it for:</p>
  593. <ul>
  594. <li>Changing the header color based on whether the answer is correct or not</li>
  595. <li>If the answer is wrong, the correct one will flash in green.</li>
  596. </ul>
  597. <p>Play with the demo below:</p>
  598. <ul>
  599. <li>Pick the wrong answer (the first and last)</li>
  600. <li>Pick the correct answer (the second one)</li>
  601. </ul>
  602. <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>
  603. <p>Here is the HTML:</p>
  604. <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>
  605. <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>
  606. <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>
  607. <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>
  608. <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>
  609. <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>
  610. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  611. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  612. <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>
  613. <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>
  614. <p>In CSS, we query the <code>.question</code> container and see if there is an answer that matches for the following:</p>
  615. <ul>
  616. <li>Checked by the user</li>
  617. <li>Has the <code>data-correct=false</code> or <code>data-correct=true</code></li>
  618. </ul>
  619. <p>If it’s false, then we add the red color.</p>
  620. <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>
  621. <span class="token selector">.questionHeader</span> <span class="token punctuation">{</span>
  622. <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>
  623. <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>
  624. <span class="token punctuation">}</span>
  625. <span class="token punctuation">}</span></code></pre>
  626. <p>And if it’s correct, the color is green.</p>
  627. <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>
  628. <span class="token selector">.questionHeader</span> <span class="token punctuation">{</span>
  629. <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>
  630. <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>
  631. <span class="token punctuation">}</span>
  632. <span class="token punctuation">}</span></code></pre>
  633. <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>
  634. <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>
  635. <span class="token selector">input[data-correct="true"] + label</span> <span class="token punctuation">{</span>
  636. <span class="token property">animation</span><span class="token punctuation">:</span> flash 1s infinite alternate<span class="token punctuation">;</span>
  637. <span class="token punctuation">}</span>
  638. <span class="token punctuation">}</span>
  639. <span class="token atrule"><span class="token rule">@keyframes</span> flash</span> <span class="token punctuation">{</span>
  640. <span class="token selector">from</span> <span class="token punctuation">{</span>
  641. <span class="token property">background-color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
  642. <span class="token punctuation">}</span>
  643. <span class="token selector">to</span> <span class="token punctuation">{</span>
  644. <span class="token property">background-color</span><span class="token punctuation">:</span> #5ed235<span class="token punctuation">;</span>
  645. <span class="token punctuation">}</span>
  646. <span class="token punctuation">}</span></code></pre>
  647. <p>How you ever come across a use case where you need to conditionally wrap a header?</p>
  648. <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>
  649. <p>See the following demo and try to toggle the checkbox on and off.</p>
  650. <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>
  651. <p>Notice how when there is a wrapper, the content is contained. The indicators on the left and right represent the space.</p>
  652. <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>
  653. <pre class="language-css"><code is:raw="" class="language-css">
  654. <span class="token selector">.siteHeader:not(:has(.headerWrapper))</span> <span class="token punctuation">{</span>
  655. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  656. <span class="token property">justify-content</span><span class="token punctuation">:</span> space-between<span class="token punctuation">;</span>
  657. <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  658. <span class="token punctuation">}</span>
  659. <span class="token selector">.siteHeader:has(.headerWrapper)</span> <span class="token punctuation">{</span>
  660. <span class="token selector">.headerWrapper</span> <span class="token punctuation">{</span>
  661. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  662. <span class="token property">justify-content</span><span class="token punctuation">:</span> space-between<span class="token punctuation">;</span>
  663. <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  664. <span class="token punctuation">}</span>
  665. <span class="token punctuation">}</span></code></pre>
  666. <p>That way, flexbox will be applied conditionally based on the presence of a wrapper.</p>
  667. <h3 id="card-thumb">Card thumb</h3>
  668. <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>
  669. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.card:not(:has(img))</span> <span class="token punctuation">{</span>
  670. <span class="token punctuation">}</span></code></pre>
  671. <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>
  672. <h3 id="card-thumb---horizontal">Card thumb - horizontal</h3>
  673. <p>Or we might need to change the card to a horizontal style if there is an image.</p>
  674. <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>
  675. <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>
  676. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">li:has(.subMenu)</span> <span class="token punctuation">{</span>
  677. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  678. <span class="token property">justify-content</span><span class="token punctuation">:</span> space-between<span class="token punctuation">;</span>
  679. <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  680. <span class="token punctuation">}</span>
  681. <span class="token selector">li:has(.subMenu) a:after</span> <span class="token punctuation">{</span>
  682. <span class="token punctuation">}</span></code></pre>
  683. <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>
  684. <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>
  685. <p>Play with the add and remove buttons in the demo to see it yourself.</p>
  686. <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>
  687. <p>This is done via the <code>:nth-last-child</code></p>
  688. <pre class="language-css"><code is:raw="" class="language-css">
  689. <span class="token selector">.submenu:has(li:nth-last-child(n + 6))</span> <span class="token punctuation">{</span>
  690. <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  691. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr 1fr<span class="token punctuation">;</span>
  692. <span class="token property">width</span><span class="token punctuation">:</span> 250px<span class="token punctuation">;</span>
  693. <span class="token punctuation">}</span>
  694. <span class="token selector">.submenu:has(li:nth-last-child(n + 8))</span> <span class="token punctuation">{</span>
  695. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr 1fr 1fr<span class="token punctuation">;</span>
  696. <span class="token property">width</span><span class="token punctuation">:</span> 350px<span class="token punctuation">;</span>
  697. <span class="token punctuation">}</span></code></pre>
  698. <h3 id="articles-section">Articles section</h3>
  699. <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>
  700. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.grid</span> <span class="token punctuation">{</span>
  701. <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  702. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr 1fr 1fr<span class="token punctuation">;</span>
  703. <span class="token property">gap</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  704. <span class="token punctuation">}</span>
  705. <span class="token selector">.article:has(img)</span> <span class="token punctuation">{</span>
  706. <span class="token property">grid-column</span><span class="token punctuation">:</span> span 2<span class="token punctuation">;</span>
  707. <span class="token property">grid-row</span><span class="token punctuation">:</span> span 2<span class="token punctuation">;</span>
  708. <span class="token punctuation">}</span></code></pre>
  709. <p>Play with the demo below:</p>
  710. <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>
  711. <p>We can take that further and make a lot of variations. For example, I want to style the grid differently if:</p>
  712. <ul>
  713. <li>There is a grid with two items</li>
  714. <li>Both items have photos</li>
  715. </ul>
  716. <h3 id="hero-section">Hero section</h3>
  717. <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>
  718. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.hero</span> <span class="token punctuation">{</span>
  719. <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  720. <span class="token punctuation">}</span>
  721. <span class="token selector">.hero:has(img)</span> <span class="token punctuation">{</span>
  722. <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 2fr 1fr<span class="token punctuation">;</span>
  723. <span class="token property">text-align</span><span class="token punctuation">:</span> start<span class="token punctuation">;</span>
  724. <span class="token punctuation">}</span></code></pre>
  725. <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>
  726. <h3 id="card-actions">Card actions</h3>
  727. <p>In this demo, we have a card with two possible states for the actions:</p>
  728. <ul>
  729. <li>One link “view recipe”</li>
  730. <li>Multiple actions: “Like, share, context menu”</li>
  731. </ul>
  732. <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>
  733. <pre class="language-css"><code is:raw="" class="language-css"><span class="token selector">.card:not(:has(img))</span> <span class="token punctuation">{</span>
  734. <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>
  735. <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>
  736. <span class="token property">max-width</span><span class="token punctuation">:</span> 250px<span class="token punctuation">;</span>
  737. <span class="token punctuation">}</span>
  738. <span class="token selector">.cardActions:has(.start, .end)</span> <span class="token punctuation">{</span>
  739. <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  740. <span class="token property">justify-content</span><span class="token punctuation">:</span> space-between<span class="token punctuation">;</span>
  741. <span class="token property">align-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
  742. <span class="token punctuation">}</span></code></pre>
  743. <p>See the demo below:</p>
  744. <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>
  745. <h2 id="outro">Outro</h2>
  746. <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>
  747. <h2 id="resources">Resources</h2>
  748. <div class="coffee-support"> <p>
  749. Enjoyed the read? If you'd like to support my work,
  750. consider buying me a coffee. <strong>This interactive guide took a month, which translates
  751. to 30 coffee cups.</strong> Thanks a latte!
  752. </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>
  753. A place where I share all the awesome CSS articles,
  754. demos, and updates that I like.
  755. </p> </div> </section> </div>
  756. </article>
  757. <hr>
  758. <footer>
  759. <p>
  760. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  761. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  762. </svg> Accueil</a> •
  763. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  764. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  765. </svg> Suivre</a> •
  766. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  767. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  768. </svg> Pro</a> •
  769. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  770. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  771. </svg> Email</a> •
  772. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  773. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  774. </svg> Légal</abbr>
  775. </p>
  776. <template id="theme-selector">
  777. <form>
  778. <fieldset>
  779. <legend><svg class="icon icon-brightness-contrast">
  780. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  781. </svg> Thème</legend>
  782. <label>
  783. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  784. </label>
  785. <label>
  786. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  787. </label>
  788. <label>
  789. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  790. </label>
  791. </fieldset>
  792. </form>
  793. </template>
  794. </footer>
  795. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  796. <script>
  797. function loadThemeForm(templateName) {
  798. const themeSelectorTemplate = document.querySelector(templateName)
  799. const form = themeSelectorTemplate.content.firstElementChild
  800. themeSelectorTemplate.replaceWith(form)
  801. form.addEventListener('change', (e) => {
  802. const chosenColorScheme = e.target.value
  803. localStorage.setItem('theme', chosenColorScheme)
  804. toggleTheme(chosenColorScheme)
  805. })
  806. const selectedTheme = localStorage.getItem('theme')
  807. if (selectedTheme && selectedTheme !== 'undefined') {
  808. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  809. }
  810. }
  811. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  812. window.addEventListener('load', () => {
  813. let hasDarkRules = false
  814. for (const styleSheet of Array.from(document.styleSheets)) {
  815. let mediaRules = []
  816. for (const cssRule of styleSheet.cssRules) {
  817. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  818. continue
  819. }
  820. // WARNING: Safari does not have/supports `conditionText`.
  821. if (cssRule.conditionText) {
  822. if (cssRule.conditionText !== prefersColorSchemeDark) {
  823. continue
  824. }
  825. } else {
  826. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  827. continue
  828. }
  829. }
  830. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  831. }
  832. // WARNING: do not try to insert a Rule to a styleSheet you are
  833. // currently iterating on, otherwise the browser will be stuck
  834. // in a infinite loop…
  835. for (const mediaRule of mediaRules) {
  836. styleSheet.insertRule(mediaRule.cssText)
  837. hasDarkRules = true
  838. }
  839. }
  840. if (hasDarkRules) {
  841. loadThemeForm('#theme-selector')
  842. }
  843. })
  844. </script>
  845. </body>
  846. </html>