Seleccionar el hermano anterior de un elemento

Seleccionar el hermano anterior de un elemento

Aprenderemos a seleccionar el hermano anterior de un elemento dentro del DOM para aplicarle estilos gracias a CSS.

En este tutorial vamos a ver cómo podemos elegir el nodo que es el hermano anterior a un elemento dentro del DOM de una página y para ello vamos a basarnos en un ejemplo formado por una serie de avatares en nuestra UI de tal manera que nuestro objetivo es que cuando el usuario haga hover sobre cualquiera de ellos este incrementará su tamaño pero también querremos que el avatar que le precede y el que le sigue también vean aumentado su tamaño.

Vamos a comenzar con el código CSS que nos permitirá mostrar cada uno de los avatares de la lista:

.avatar {
  /** Otras propiedades CSS */
  transition: scale 500ms;
}

.avatar:hover {
  /** Otras propiedades CSS */
  scale: 2;
}

Nota: únicamente vamos a mostrar el código CSS que es relevante para la explicación que vamos a realizar con el fin de no alargar demasiado la explicación.

Como podemos observer en nuestro código CSS estamos defiendo una transition de CSS de tal manera que cuando se produzca un cambio en la escala de un elemento marcado con la clasee avatar lo que sucederá es que dicha transición durará medio segundo y no solamente eso sino que además cuando se produce el evento hover lo que sucederá es que el avatar pasará a tener un escala 2 (duplicará su tamaño) pero no de forma automática sino que el cambio se producirá una vez transcurrido medio segundo.

Seleccionar el avatar de la derecha

Para poder seleccionar el avatar de la derecha vamos a hacer uso del operador adyacente de CSS, es decir, el operador + que lo que viene a hacer es seleccionar un elemento que es hermano adyacente (por la derecha) de otro elemento.

Sabiendo esto ¿cómo nos lo llevamos a nuestro ejemplo? Pues pensemos que lo que queremos es que avatar que es adyacenten por la derecha de otro avatar vea incrementada su escala, es decir, que en principio podríamos pensar en algo como esto:

.avatar + .avatar {
  scale: 1.5;
}

pero si hacemos eso lo que lograremos es que ya de principio la estacala de este avatar adyacente por la derecha se vea incrementado en un 1.5 cosa que no es nuestro objetivo puesto que nosotros queremos que esto se produzca cuando se hace hover. Así pues modificamos la regla CSS para que quede de la siguiente manera:

.avatar:hover + .avatar {
  scale: 1.5;
}

Con esto lograremos el efecto que vemos en la siguiente imagen y ya tendríamos resuelto nuestro problema en el caso del avatar de la derecha:

Seleccionar el avatar de la izquierda

¿Qué podemos hacer para seleccionar el avatar de la izquierda? Pues vamos a usar el selector has() que nos ofrece CSS. En concreto lo que hacemos es escribir la siguiente regla CSS:

.avatar:has(+ avatar:hover)

¿Confundido? ¡Normal! Esto es un poco tricky pero vamos a intentar entenderlo. Lo que hacemos es aplicar a cada uno de los elemento avatar que tengamos en la interfaz la función has() pasándole como parámetro un avatar sobre el que se esté produciendo el evento hover. Dicho de otra manera, lo que estamos seleccionando es un avatar que va seguido (recuerda cómo se usa el operador + de CSS) de otra avatar sobre el que tenemos el evento hover por lo que, si lo pensamos un poco, en realidada estamos haciendo referencia al avatar que está precediendo al avatar sobre el que se produce el evento hover (el que está situado a su izquierda).

Por lo tanto podemos amplicar nuestra definición de las reglas CSS como sigue:

.avatar {
  /** Otras propiedades CSS */
  transition: scale 500ms;
}

.avatar:hover {
  /** Otras propiedades CSS */
  scale: 2;
}

.avatar:has(+ avatar:hover)
.avatar:hover + .avatar {
  scale: 1.5;
}

y ahora lograremos el efecto que estábamos persiguiendo cuando hemos planteado inicialmente nuestro problema:

Soporte para todos los navegadores

¿Podemos estar seguros de este código va a funcionar en todos los navegadores? No, pero sí que podemos protegernos para que únicamente sea utilizado en aquellos que lo soportarán ¿cómo lo hacemos? Pues utilizando la regla @supports que nos proporciona CSS la cual está pensada para verificar que su contenido se aplicará si un navegador es compatible con una cierta característica de CSS.

Lo que queremos ver es si el navegador es compatible con la función has() de CSS la cual es un selector de CSS por que podemos escribir algo como:

@supports selector(:has()) {

es decir, que queremos que las reglas que se engloben ahí dentro se apliquen únicamente en el caso de que el navegador entienda lo que hace la función has() pero podemos ir un poco más adelante y especificar qué selector ha de a su vez entender has() que en nuestro caso será el operador adyancente (+) seguido de cualquier elemento. Esto se escribe de la siguiente manera:

@supports selector(:has(+ *)) {

Ahora ya solamente nos quedará encerrar las reglas CSS que hemos definido anteriormente aquí dentro para lograr el objetivo que estamos persiguiendo:

.avatar {
  /** Otras propiedades CSS */
  transition: scale 500ms;
}

.avatar:hover {
  /** Otras propiedades CSS */
  scale: 2;
}

@supports selector(:has(+ *)) {
  .avatar:has(+ avatar:hover)
  .avatar:hover + .avatar {
    scale: 1.5;
  }
}

Nota: @supports es lo que se conoce como una Feature Query en CSS.

Nota: si quieres ver en mayor profundidad cómo funciona la función has() de CSS puedes echarle un vistazo a este otro artículo del blog "La Funcion has() de CSS".