:is(), :where() & :not()
The :is(), :where(), and :not() pseudo-classes simplify complex selectors. :is() reduces repetitive selectors, :where() does the same with zero specificity, and :not() excludes elements from selection.
Selector Simplification
- :is(h1, h2, h3) — Matches any of the listed selectors. Reduces duplication
- :is() specificity — Takes the HIGHEST specificity of its arguments. :is(#id, .class) has ID specificity
- :where() — Same as :is() but with ZERO specificity! Always overridable. Great for resets and defaults
- :not(.active) — Excludes elements matching the selector
- :not(:first-child):not(:last-child) — Select all middle children
- Nesting with :is() — article :is(h1, h2, h3) replaces writing article h1, article h2, article h3
- Combine them — :is(h1, h2):not(.small) selects h1/h2 without .small class
Simplification Code
/* Without :is() — repetitive */
article h1, article h2, article h3,
section h1, section h2, section h3 {
color: #1a1a2e;
}
/* With :is() — clean! */
:is(article, section) :is(h1, h2, h3) {
color: #1a1a2e;
}
/* :where() for overridable defaults */
:where(h1, h2, h3) {
margin-top: 0;
line-height: 1.2;
/* Zero specificity — easy to override anywhere */
}
/* :not() patterns */
.nav-link:not(.active) { opacity: 0.7; }
li:not(:last-child) { border-bottom: 1px solid #eee; }
input:not([type="checkbox"]):not([type="radio"]) { width: 100%; }Tip
Use :where() for CSS resets (zero specificity — any class overrides it). Use :is() for component styles where you want normal specificity. This distinction is the key to managing specificity in large projects.
Higher specificity wins when multiple rules target the same element
Common Mistake
:is() takes the HIGHEST specificity of its arguments. :is(#id, .class) gives ID-level specificity to the entire selector. Use :where() if you want zero-specificity grouping. This subtle difference causes unexpected override issues.
Practice Task
Refactor repetitive selectors: (1) Replace 'article h1, article h2, section h1, section h2' with :is(article, section) :is(h1, h2), (2) Create a zero-specificity reset with :where(), (3) Use :not(:last-child) for borders between list items.
Quick Quiz
Key Takeaways
- The :is(), :where(), and :not() pseudo-classes simplify complex selectors.
- :is(h1, h2, h3) — Matches any of the listed selectors. Reduces duplication
- :is() specificity — Takes the HIGHEST specificity of its arguments. :is(#id, .class) has ID specificity
- :where() — Same as :is() but with ZERO specificity! Always overridable. Great for resets and defaults