Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Modern selectors

Pseudo-classes like :hover and :first-child check the state or position of an element. The newer pseudo-classes take other selectors in parentheses and allow what used to be impossible: for example, picking a parent by what lies inside it. All of them work in modern browsers.

:is() — one of a list

:is() matches if the element matches any selector from the list. It cuts repetition:

<style>
  :is(h2, h3, h4) { color: steelblue; margin: 4px 0; }
</style>
 
<h2>Heading h2</h2>
<h3>Heading h3</h3>
<h4>Heading h4</h4>
<p>The paragraph did not change</p>

Without :is() you would write h2, h3, h4. The gain shows in long chains: .post :is(h2, h3) a instead of .post h2 a, .post h3 a.

:where() — the same, but weightless

:where() selects the same things as :is(), but its specificity — the strength of a selector in the cascade — is always zero. Any other rule easily overrides it, so :where() is handy for base styles:

<style>
  :where(.article) a { color: seagreen; }
  a { color: crimson; }
</style>
 
<p class="article"><a href="#">The link is red</a>: the simple selector a beat the rule with :where().</p>

:not() with a list

:not() selects elements that do not match a selector. Several selectors can be listed inside with commas:

<style>
  li:not(:first-child, .muted) { color: crimson; }
</style>
 
<ul>
  <li>The first — not red</li>
  <li>The second — red</li>
  <li class="muted">Muted — not red</li>
  <li>The fourth — red</li>
</ul>

:has() — selecting by content

:has() selects an element that contains something matching a selector. It is called the "parent selector": CSS used to look only down the tree, and now it can look up as well:

<style>
  .card { padding: 12px; margin-bottom: 8px; border: 2px solid silver; }
  .card:has(svg) { border-color: gold; }
</style>
 
<div class="card">A card without a picture</div>
<div class="card">
  <svg width="40" height="40"><circle cx="20" cy="20" r="18" fill="gold"/></svg>
  A card with a picture
</div>

:has() arrived in all major browsers at the end of 2023.

:has() and form state

:has() reacts to changes: a parent can restyle itself when a checkbox inside is ticked. Click the checkbox:

<style>
  .option { padding: 12px; border: 2px solid silver; }
  .option:has(input:checked) { border-color: seagreen; background: honeydew; }
</style>
 
<label class="option">
  <input type="checkbox"> Courier delivery
</label>

This effect used to require JavaScript.

Common mistake

The specificity of :is() equals the strongest selector in its list. If an id gets into the list, the rule becomes very heavy and beats classes, even when it stands above them:

<style>
  :is(#intro, p) { color: crimson; }
  .note { color: seagreen; }
</style>
 
<p class="note">We wanted green, but got red</p>

Here the paragraph is selected through p, but the whole :is() got the weight of an id. Do not mix ids and simple selectors in one :is(), and use :where() for light rules.

Thanks for reading!

Donate to the site — we work hard for you.