07 · Selectors

Selectors

Logical selectors that replace state JS

:has() Chrome 105+ · :is()/:where()/:not() wide support
← Index

:has()

The "parent selector" CSS never had. Style an element based on its content.

Card without icon

Normal background.

This one has a .badge → the whole card changes border and background.

article:has(.badge) { border-color: amber }

:is() / :where()

They group selectors. :is() keeps specificity; :where() resets it to 0.

Heading with :is()

Paragraph with :is()

Link with :is()

:is(h4, p, a).target { color: amber }

:not()

Excludes elements. Here all items have a border except the one with .skip.

  • Normal item
  • Normal item
  • Normal item

li:not(.skip) { border-left: amber }

css
/* :has() — estilá según el contenido */
.card-demo:has(.badge) {
  border-color: rgba(245, 158, 11, .5);
  background: rgba(245, 158, 11, .08);
}

/* :is() — agrupa selectores, mantiene specificity */
:is(h4, p, a).target {
  color: var(--amber-soft);
  font-weight: 600;
}

/* :not() — excluye elementos */
li:not(.skip) {
  border-left: 3px solid var(--amber-500);
}

An honest note on support

Many of these APIs are recent and not yet in every browser (see the pill on each section). The nice part is they all degrade gracefully: the carousel still scrolls, the accordion opens/closes, the textarea works — just without the animated "plus".