🎛️ CSS

Advanced CSS Selectors — :has, :is, :where and :not in Practice

📅 Jul 3, 2026 ⏱ 3 min read

Four modern selectors eliminate whole categories of JavaScript and class-juggling.

:has() — the parent selector (finally!)

/* card that CONTAINS an image gets different padding */
.card:has(img) { padding: 0; }

/* form label turns red when ITS input is invalid */
label:has(+ input:user-invalid) { color: #ef4444; }

/* page freezes scrolling when a modal is open — no JS! */
body:has(dialog[open]) { overflow: hidden; }

:is() — stop repeating yourself

/* before */
article h1, article h2, article h3 { margin-top: 2rem; }
/* after */
article :is(h1, h2, h3) { margin-top: 2rem; }

:where() — same, but zero specificity

Perfect for resets and libraries: :where(ul, ol) { margin: 0 } is trivially overridable by any user class — no specificity fights.

:not() with lists

button:not(.primary, .danger) { background: gray; }
li:not(:last-child) { border-bottom: 1px solid #eee; }

All four work in every modern browser. Full selector reference: Complete CSS Guide §02.

← All Articles