:has() relational selector
Baseline 2023 (Chrome 105, Safari 15.4, Firefox 121); disponible de forma generalizada.
Chrome 105
Edge 105
Safari 15.4
Firefox 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.
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.
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))`.