← Back to CSS
53

Advanced selectors: `:has()`, `:is()`, `:where()` and `:not()`

Master modern functional selectors to reduce duplication, control specificity and build visual logic without JavaScript.

📘 Theory

`:has()` for layout and state decisions

Style the current element only when an internal condition is true.

For years CSS could not select a parent according to what happened inside it. `:has()` changes that and opens patterns that previously required JavaScript.

The right mental model is `element:has(condition)`. If the condition is true, the main element gets styled.

In `.card:has(img)`, you are not selecting the image. You are selecting the card because of its content. In forms, `form:has(:invalid)` makes global feedback much easier.

  • Syntax: `element:has(selector)`.
  • Typical cases: cards with or without media, menus with submenus, forms with validation errors.
  • You can combine `:has()` with `:not()`: `article:not(:has(img))`.
  • Keep the scope component-based: `.checkout-form:has(:invalid)` is usually better than a broad global rule.
  • Support is strong in modern browsers, but still worth checking for production requirements.

`:is()`, `:where()` and `:not()`: group and exclude strategically

Same maintenance goal, different specificity behavior.

Use `:is()` to group equivalent selectors without repeating long prefixes.

Use `:where()` for low-priority base styling that should stay easy to override because its specificity is zero.

Use `:not()` to exclude concrete variants without cloning broad rules.

  • `:is(a, b, ...)`: groups selectors and keeps the strongest specificity among its arguments.
  • `:where(a, b, ...)`: groups selectors with zero specificity.
  • `:not(...)`: explicit and maintainable exclusion.
  • Practical rule: base with `:where()`, variations with classes.

Specificity strategy and good practice

Prevent specificity wars before they start.

1

If a rule is foundational, such as default typography or spacing, prefer `:where()` so the next layer of the UI can override it cleanly.

2

Reserve `:is()` for grouping inside components or layout structures, and pair it with classes for state-driven UI behavior.

3

Avoid very complex chains such as `:has(:not(...):is(...))` unless they truly solve a real maintenance problem. Readability is part of maintainability.

Validation pseudo-classes in forms

Style inputs according to `required`, patterns and built-in HTML validation.

HTML5 validation exposes useful states to CSS: `:valid`, `:invalid`, `:required` and `:optional`.

When you combine those states with `:has()`, the submit button or the field wrapper can react without any scripting.

  • `:valid` and `:invalid`: depend on whether the value satisfies the constraints.
  • `:required` and `:optional`: depend on the presence of the `required` attribute.
  • Avoid styling `:invalid` too aggressively before real interaction. Pair it with `:focus` or `:not(:placeholder-shown)` when necessary.

🧭 Key visuals

Advanced selectors and priority

Helps you decide when selector simplification leads to cleaner overrides.

Comparison of compound selectors and their impact on specificity.

Map of advanced selectors

Works as a quick cheat sheet for combinators, functional selectors and the contexts where they add real precision.

Visual overview of advanced CSS selectors and their practical use cases.

Pseudo-classes and pseudo-elements

Clarifies one of the most common points of confusion when selectors become more expressive.

Comparison between pseudo-classes and pseudo-elements in CSS.

🧪 Learn by doing

Example Demo: decisions with `:has()` plus grouping with `:is()` Toggle a visual mode and check shared styles without duplicating selectors.
Example Interactive demo: contextual form The container changes when there is focus or an error state.

🏁 Challenges

Challenge Challenge: form with `:has(:invalid)` Visually disable the button when the form contains invalid fields using `form:has(:invalid) .btn-submit`.
Challenge Challenge: exclusion with `:not()` Apply a neutral style to every button except the primary and danger variants.
Challenge Challenge: conditional card Highlight `.card` only if it contains an image.

What is this?

I'm Cristian Eslava and I sometimes build websites so both you and I can learn and experiment. culTest

I made this in February 2026 to make learning easier for my students. The idea is to learn web development by practicing and to keep expanding the project with new topics, tests and challenges.

It draws inspiration from MDN, W3Schools, CodePen, Manz and many other web development references. I wanted to combine useful theory, runnable examples, challenges and the testing system I had already built for culTest. culTest

If you liked it, if you didn't, or if you want to get in touch, write to me at cristianeslava@gmail.com