Ya vimos en el post de novedades CSS 2024 como ahora :has()
ya tiene implementación en todos los navegadores, así que podemos comenzar a usarlo. Esto nos ofrece un montón de posibilidades nuevas que vamos a ver en este artículo.
Entre otras cosas, esto nos va a hacer escribir menos JavaScript para manipular el DOM y estar añadiendo y quitando clases. Pero bueno, vamos al lío, veamos una serie de ejemplos sobre cómo usar :has()
.
Se puede dar el caso en el que dentro de una misma web las páginas sean diferentes, con diferente color de fondo de manera que tengamos que utilizar un logo y en otra página la versión invertida (la clara o la oscura). Antes, para esto, teníamos que escribir parte de JavaScript condicionando a depende qué página. Ahora podríamos hacer algo tal que así:
<style>
.logo {
width: 100px;
height: 100px;
background-color: #bbb;
}
body:has(.pagina-clara) .logo {
background-color: #000;
}
</style>
<header>
<div class="logo">
<img src="logo.png" alt="Logo de la empresa" />
</div>
</header>
<main>
<section class="pagina-clara">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
</section>
</main>
Hemos hecho un ejemplo sencillo usando background-color, pero podría cambiarse el estilo por “background: url(‘nuestro-logo.png’)
o usando un filter: invert()
por ejemplo.
Otro uso que se le puede dar al :has()
es el hecho de que el hermano del elemento que cumpla la condición reciba los estilos, he cogido este código de StackOverflow y lo he adaptado un poco:
See the Pen Untitled by David Boo (@David-Boo) on CodePen.
En este caso que planteamos, al hacer hover sobre uno de los elementos, el contrario recibe los estilos Podría hacerse también de forma que ambos elementos recibieran dichos estilos por ejemplo.
Es muy útil, especialmente con los label de los elementos inputs. Muchas veces nos encontramos formularios con los inputs dentro del label, pero muchas otras es fácil encontrarse estos como elementos hermanos. Quizá porque puedas tener también algún elemento HTML en medio o por alguna otra razón, como que sea, por ejemplo, un plugin de WordPress que viene así definido. Así que, para dar estilos a la etiqueta en función del estado del input, podemos hacerlo con :has
de esta forma:
<style>
label:has(+ input:invalid),
label:has(+ input:invalid)::before {
content: "✖ ";
color: red;
}
label:has(+ input:valid),
label:has(+ input:valid)::before {
content: "✓ ";
color: green;
}
</style>
</head>
<body>
<form>
<div>
<label for="email">Email: </label>
<input type="email" id="email" required />
</div>
</form>
</body>
Es más, podríamos ir un poco más allá y cambiar directamente el color del botón para que el usuario se percate que el formulario tiene algún campo que no es válido:
See the Pen Untitled by David Boo (@David-Boo) on CodePen.
Esta me parece particularmente interesante. Para hacer esto antes se ha necesitado utilizar JavaScript o crear un contendor que contenía todos los elementos sobre los que hacer hover y, al entrar al contendor con el cursor, ya se aplicaban los estilos a todos los demás. Con la pseudo-clase :has
eso cambia. Ahora vamos a poder hacer hover sobre un elemento y aplicar los estilos en todos los demás. He aquí un ejemplo con el código:
See the Pen Untitled by David Boo (@David-Boo) on CodePen.
La parte interesante de todo esto es el selector que hace esto posible:
.card:has(~ .card:hover),
.card:hover ~ .card:not(:hover)
El primero selecciona todos los hermanos anteriores del elemento al cual se aplica el hover y el segundo lo aplica a los posteriores.
Combinando :nth-child
y :has()
podemos dar estilos en función a la de número de elementos que tenga un contenedor, sería tan sencillo como seleccionar el contenedor y preguntarle si contiene un “n” número de hijos, de esta forma:
.container:has(nth-child(10))
Así, si contiene un décimo hijo, es que tiene al menos 10. Vamos con un ejemplo:
See the Pen Untitled by David Boo (@David-Boo) on CodePen.
Vemos como en el ejemplo, según vamos aumentando el número, los bloques van cambiando de color y haciéndose más pequeños. En este caso hemos utilizado como selector el propio div, pero podría usarse también el selector universal (*) para que esto pasase si tuviera elementos de cualquier tipo. Combinado con grid podríamos incluso disponer los elementos de forma diferente dependiendo del número que fueran sin tener que usar JavaScript.
En las barras de navegación con submenús, suele aparecer un indicador de que un elemento de la lista contiene un submenú, con :has() podemos darle estilos muy fáciles de esta manera:
nav ul li:has(ul) {
position: relative;
}
nav ul li:has(ul):after {
content: "⌄";
position: absolute;
color: #fff;
right: 0;
top: 50%;
transform: translateY(-50%);
}
Así que, si un elemento de la lista li
contiene un ul
, entonces le añadimos la flechita que indica que en dicho elemento tenemos un submenú que se va a desplegar.
Estas son unas ideas de uso de :has()
, a lo mejor a partir de ahora te vas a preguntar un par de veces si puedes resolver estas situaciones directamente con CSS sin tener que pasar por usar JavaScript en estos casos a la hora de realizar tus diseños y desarrollos web.
¡Te animamos a que pruebes esta propiedad de CSS tan interesante!
En este artículo, aprenderás qué es el Lazy Loading y cómo implementarlo fácilmente en tu… Leer más
En esta guía práctica, te explicamos qué es el presupuesto de rastreo, por qué es… Leer más
¿Alguna vez te has encontrado con un mensaje que te invita a actuar, ya sea… Leer más
Una de las preguntas más comunes entre los desarrolladores web que comienzan a usar JavaScript… Leer más
Descubre qué es y para qué sirve la preimpresión digital para conseguir una buena impresión… Leer más
Ampliamos información para las redes sociales. Descubre cómo gestionar correctamente los consentimientos necesarios en las… Leer más