Qué es y ejemplos de cómo usar :has(), la pseudo-clase de CSS

Qué es y ejemplos de cómo usar :has(), la pseudo-clase de CSS

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().

Ejemplos sobre cómo usar :has()

Cómo mostrar un logo diferente en cada página

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.

Uso de :has() con el selector de hermanos adyacentes (+)

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.

Cómo dar estilos a elementos label

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.

Cómo seleccionar todos los elementos hermanos de otro destacado (hover) en CSS usando la pseudoclase :has()

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.

Cómo generar quantity queries con :nth-child y :has()

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.

Cómo añadir indicadores en menú dropdown

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.

Conclusión

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!

Dejar una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Puedes usar estas etiquetas y atributos HTML:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>