A structured lesson workspace with readable content, hands-on examples, and a clean path to completion.
<style>.card :is(h2, h3, h4) { margin-block-end:.5rem; }</style><main class="card">Example content</main>
Engineering judgment: These selectors reduce duplication, but they also make selector intent more powerful. Keep the relationships understandable for maintainers.
A good CSS change narrows the problem. These selectors reduce duplication, but they also make selector intent more powerful. Keep the relationships understandable for maintainers. This keeps the rule understandable when content, theme, or viewport conditions change later.
<style>.prose :where(ul, ol) { padding-inline-start:1.25rem; }</style><main class="demo"><ul><li>First item</li><li>Second item</li></ul></main>
In production, The four functions are not interchangeable. :is() adopts the specificity of its most specific argument, while :where() contributes zero specificity; :has() selects based on a relative selector list. That is the kind of bug that survives visual spot checks because the stylesheet is syntactically valid while the layout contract is wrong.
| Concern | What to inspect | Typical failure |
|---|---|---|
| Core behavior | The :is(), :where(), :has(), and :not() Selectors | The four functions are not interchangeable. :is() adopts the specificity of its most specific argument, while :where() contributes zero specificity; :has() selects based on a relative selector list. |
| Production test | Real content and constraints | The rule works only for the demo values |
| Maintenance | Scope and override path | A later fix creates another exception |
The useful mental model here is practical: how modern selector functions compress selector lists, control specificity, inspect descendants, and exclude matches. When a rule looks obvious but the browser produces something else, start by identifying which constraint or rendering phase is actually winning.
<style>.field:has(input:invalid) { border-color:crimson; }</style><main class="demo"><label>Example field <input class="demo-input" type="text"/></label></main>
:has() is useful here because it demonstrates the :is(), :where(), :has(), and :not() selectors under a concrete input rather than as an abstract property list.
<style>.nav a:not(.is-current) { opacity:.8; }</style><main class="demo"><a href="#">Example link</a></main>
:not() is useful here because it demonstrates the :is(), :where(), :has(), and :not() selectors under a concrete input rather than as an abstract property list.
Finish the lesson once you have worked through the material. This awards ★ 30 XP.