Cómo y cuándo utilizar :has()
Tabla de contenido
El año 2023 debía de ser el año de :has()
una función de CSS que permite evaluar si un selector “contiene algún otro elemento”, útil para aplicar estilos a un contenedor en función de su contenido, algo parecido al selector padre que nunca llegó a CSS (ni llegará), pero tuvimos que esperar hasta final de año para poder usarlo a discrección, y es que fue entonces cuando Firefox lo implementó y quedaba por fin ampliamente cubierto por la gran mayoría de navegadores. CanIUse
Hasta ese momento podíamos usarlo o bien para detalles estéticos que no fueran críticos y asumir que habría usuarios que no lo verían, o bien ofrecer una alternativa (fallback) usando javascript, lo que suponía añadir complejidad al asunto (a menudo no necesaria) aumentando el riesgo de fallar, porque codificar nos empuja a la posibilidad de cometer errores, ¿no?
Así que este artículo llega con un año de retraso pero al mismo tiempo llega más maduro.
Casos de uso
:has()
acepta como argumento una lista de selectores relativos (<relative-selector-list>
) y comprueba si al menos uno de ellos coincide con el DOM. Si la condición se cumple.
El ejemplo sencillo sería p:has(> a)
en el que se evalúa si un párrafo contiene un enlace. La diferencia con p > a
es que en el primer caso estamos seleccionando el p
mientras que en el segundo los estilos se aplican a a
que es el elemento seleccionado. Por eso decimos que podemos aplicar estilos condicionalmente en función de su contenido o que es como un selector padre.
Pero es algo más.
Como el selector es relativo, el argumento hace relación al elemento que evalúa (el que lo usa), pero podríamos querer aplicar estilos a un elemento hermano en función de si el anterior (o padre) tiene alguna particularidad, por ejemplo: section:has(.box) + section
A partir de aquí, puedes intentar las queries más raras que se te ocurran, algunas funcionarán y otras no o no a la primera, sobre todo son difíciles las que involucran todas las pseudo-clases del estilos nth-of-type()
pero algunas de las más comunes son, por ejemplo:
Comprobar si un elemento contiene otro
Evaluar si un elemento contiene otro elemento, clase u atributo.
article:has(h1, h2, h3, h4, h5, h6)
section:has([class^="item"]) li[class]
Comprobar si un elemento NO contiene otro
Podemos también evaluar si un elemento no contiene otro elemento, clase u atributo.
figure:not(figcaption)
Hay que prestar atención al combinarlo con :not()
porque el orden de declaración altera el sentido de la expresión, no es lo mismo li:not(:has(span))
que li:has(:not(span))
porque no es lo mismo que no contenga span
a que contengan cualquier cosa que no sea un span
.
Contar hijos
Podemos evaluar el número de hijos que tiene un nodo para aplicar una solución tipo flex
o grid
.
ul {
display: flex;
}
ul:has(> :nth-child(5)) {
display: grid;
grid-template-columns: 1fr 1fr;
}
Comprobar si hay elementos abiertos
Como podemos evaluar clases o atributos, es una solución ideal para bloquear el scroll de la página cuando un elemento emergente está abierto.
body:has(.is-modal-open) {
overflow-y: hidden;
}
body:has(dialog[open], details[open]) {
overflow-y: hidden;
}
body:has([aria-expanded="true"]) {
overflow-y: hidden;
}
Peculiaridades
Por supuesto no todo es jauja, hay ciertas limitaciones

:has()
no se puede anidar, así que selectores de este estilo no funcionarán
body:has(section:has(span)) {
outline: 10px solid lime;
outline-offset: -12px;
}
:has()
no puede evaluar pseudo-elementos (esos elementos que son virtuales) porque no los puede evaluar en el DOM.
body:has(::before) {
color: #f06;
}
Demo
Aquí una pequeña demo para que puedas probar lo explicado anteriormente.
Para ampliar más
Las combinaciones de :has()
son muchas, tantas que rara vez las necesitarás usar porque podrás poner solución con otras herramientas o enfoque, pero conviente saber hasta dónde se puede llegar a estresar. Para ampliar más, no se me ocurre mejor lugar bram.us donde encontrarás una amplia colección de artículos relacionados, en los que se lleva la capacidad de :has()
muy al límite.
Recursos
comments powered by DisqusSi te ha parecido interesante
Tanto si tienes alguna duda o te apetece charlar sobre este tema, así como si el contenido te parece interesante o crees que pdemos hacer algo juntos, no dudes en ponerte en contacto con nosotros a través de del email hola@mamutlove.com