:has() relational selector

Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121); disponible de forma generalizada.

Chrome 105Edge 105Safari 15.4Firefox 121

Selecciona un elemento según lo que contiene o lo que le sigue, algo que CSS nunca pudo hacer antes ("una tarjeta que tiene imagen", "un campo de formulario cuyo input es inválido", "la etiqueta antes de un checkbox marcado"). Sustituye a una buena parte de las clases de estado en JS.

Shipping
CSS
.fx-002 {
  font-family: system-ui;
  display: grid;
  gap: 12px;
  max-width: 360px
}
.fx-002 fieldset {
  opacity: .4;
  pointer-events: none;
  transition: opacity .2s
}
.fx-002:has(input[type=checkbox]:checked) fieldset {
  opacity: 1;
  pointer-events: auto
}
.fx-002 fieldset:has(input:user-invalid) {
  border-color: #c0392b
}
.fx-002 :is(a,button,input,select,textarea):focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
HTML
<form class="fx-002">
  <label><input type="checkbox"> Enable shipping address</label>
  <fieldset><legend>Shipping</legend><input placeholder="Street" required></fieldset>
</form>

Fallback: Envuélvelo en `@supports selector(:has(a))` si el estado sin :has debe ser distinto; si no, el fieldset simplemente se queda habilitado.

Fuente: developer.mozilla.org/en-US/docs/Web/CSS/:has

Prompt

Usa `:has()` para estilos que dependen del padre o de hermanos en vez de alternar clases con JavaScript: por ejemplo `form:has(input[type=checkbox]:checked) fieldset` para mostrar una sección, `.card:has(img)` para variantes con media, `label:has(+ input:focus-visible)` para etiquetas enfocadas. Mantén el argumento de `:has()` poco profundo (uno o dos selectores compuestos) por rendimiento y protege los layouts no triviales con `@supports selector(:has(a))`.