en CSS

Selectores avanzados CSS 1/4 – nth-child()

En este tutorial vamos a ver algunos de los selectores CSS avanzados menos conocidos y sus usos prácticos. En concreto en este artículo que nos ocupa veremos las diferentes variantes de :nth-child.

Selectores :nth-child de básico a avanzado

Nos permiten seleccionar elementos o series de elementos dentro de una o múltiples colecciones haciendo referencia a la relación de posición del elemento seleccionado respecto de sus hermanos. Entendiendo como hermanos todos aquellos elementos hijos directos del mismo nodo del DOM.

:nth-child() básicos

Comenzamos repasando algunos conceptos para aquellos que no hayan trabajado aún con :nth-child() e iremos subiendo la complejidad paulatinamente.

:nth-child(n) y :first-child

Nos permiten seleccionar un elemento particular en función de su posición relativa al total de la colección o colecciones que coincidan con el selector. Por ejemplo:

li:nth-child(2) {
 color: aqua;
}

Seleccionará cualquier li que se encuentren en la posición 2 dentro de un mismo nodo del DOM.

select second elment with nth-child(2)

:first-child es quivalente a :nth-child(1), o lo que es lo mismo, selecciona el primer elemento de ese nodo.

:nth-child(n) será la base para entender el resto de selectores que veremos.

Ambos selectores encuentran una de sus aplicaciones más útiles en listas de productos, especialmente cuando son tipo grid (cuadricula). Cuando, por ejemplo, deseamos destacar los primeros elementos de la lista dándoles un formato más prominente.

:last-child y :nth-last-child(n)

Funcionan exactamente igual que los anteriores pero empezando por el final de la colección.

:nth-child(An+B)

Nos permitirá seleccionar múltiples elementos añadiendo dos condiciones: alternancia e inicio de la selección. El número (A) que multiplica a n será el que determine cuántos elementos saltar en la selección mientras que el que sumamos (B) será la posición de inicio. De esa forma n+1 seleccionaría todos los elementos, mientras que 2n+2 seleccionará cada dos elementos comenzando a partir del segundo de la colección.

Imagina una lista de personajes listados en sus tres niveles adquiribles a precios distintos, siendo cada nivel un registro de la misma tabla de precios de una base de datos, cada uno de los cuales está a su vez enlazado por ID a otra tabla que define sus características. El bucle te devuelve sólo una lista con todos los niveles ordenados por el nombre (Jason 1, Jason 2, Jason  3…), pero el diseño ha definido para cada uno de los tres niveles un estilo diferente. La forma más sencilla de resolverlo sería usando :nth-child(An+B)

HTML devuelto por el bucle

<ul class="grid">
  <li>Chucky 1</li>
  <li>Chucky 2</li>
  <li>Chucky 3</li>
  <li>Fredy 1</li>
  <li>Fredy 2</li>
  <li>Fredy 3</li>
  <li>Jason 1</li>
  <li>Jason 2</li>
  <li>Jason 3</li>
</ul>

CSS necesario para seleccionar los elementos correspondientes a cada columna:

.grid li:nth-child(3n+1){
  background-color: sandybrown;
}
.grid li:nth-child(3n+2){
  background-color: silver;
}
.grid li:nth-child(3n+3){
  background-color: gold;
}

Resultado:

Como veréis esto ahorra atributos class y, por lo tanto, peso del documento HTML y, como podréis imaginar un ahorro en lógica dentro del loop que lo deja más limpio, y lo que es aún más importante, separado de cuestiones estéticas que son asunto del CSS.

:nth-child(odd/even)

«Odd» y «even» son una simplificación de los valores 2n+1 y 2n+2 respectivamente, es decir, el primero seleccionará impares y el segundo pares.

Probablemente los más utilizados de los anteriores, siendo su uso más común el de crear el efecto pijama de las tablas de datos.

:nth-child() avanzados

:nth-child(-n+B) y :nth-last-child(-n+B)

La lógica es la siguiente: comenzando a partir del elemento B, selecciona todos los elementos anteriores en función de si cuenta desde el principio o desde el final. O lo que es lo mismo, selecciona los primeros o últimos B elementos

Ejemplo selección n primeros elementos

Por supuesto también podemos añadirle alternancia seleccionando cada, p.e. 3 elementos. Así :nth-child(-3n+9) seleccionará uno de cada 3 elementos contando hacia atrás desde el 9 inclusive.

:only-child y :only-of-type

Probablemente uno de los más raros de ver a pesar de su utilidad. :only-child nos permite identificar cuando un elemento es el único hijo directo de su padre. :only-of-type añade la condición de tipo, de forma que aún habiendo más elementos hermanos, si es el único de su tipo, podremos darle estilos diferentes.

Yo uso :only-child  principalmente para evitar grandes espacios en blanco en listados con un único resultado y hacer más cómoda para el usuario la visualización de la información.

Tanto :only-child como :only-of-type me ha sido muy útiles incontables veces cuando trabajo con módulos cuyos elementos son prescindibles y pueden aparecer o no según los requerimientos de información de cada apartado. Por ejemplo si en un listado con acciones puedes tener muchos botones en unas ocasiones y en otras sólo uno, lo escondes en el primer caso y lo dejas visible en segundo. O en un módulo de botones de formulario, cuando tienes varios les das una longitud flexible mientras que cuando sólo tienes uno le das un width: 100% o le fijas un ancho. Y podría seguir poniendo ejemplos…

Y llegamos a la guinda del pastel de :nth-child(), el parámetro «of <selector>». Antes de nada apuntar que el soporte de navegadores para este selector se limita, de momento, a Safari. Sin embargo Chrome volvió a reabrir el ticket de desarrollo para esta funcionalidad en Dic. 2019, y parece que hay  interés reciente entre la comunidad de FF. Crucemos los dedos para ver si implementan esta recomendación del W3C.

Dicho esto, seguramente algunos habréis caído en la similitud con selector:nth-child(), así que voy a explicar las diferencias entre uno y otro y lo voy a hacer con una imagen que lo ilustrará mejor que las palabras.

Dado el siguiente HTML

<ul class="row">
  <li class="test">Item 1</li>
  <li>Item 2</li>
  <li class="test">Item 3</li>
  <li>Item 4</li>
  <li class="test">Item 5</li>
  <li>Item 6</li>
</ul>

CSS 1: of <selector> (Actualmente sólo funciona en Safari)

:nth-child(-n+3 of .test) {
  background: aqua;
  /* Selecciona los tres primeros elementos .test que encuentra en la colección */
}

Ejemplo de los 3 primeros elementos de un tipo encontrados

CSS 2

.test:nth-child(-n+3) {
  background: aqua;
  /* Selecciona dentro de los tres primeros elementos aquellos que corresponden con .test */
}

Ejemplo selección de todos los elementos que coincidan con una clase dentro de los n primeros elementos

Ambos métodos pueden ser muy interesantes, aunque de momento sólo el segundo tenga soporte total de los navegadores.

Espero que os haya sido útil, en la próxima entrega veremos y aprenderemos a usarlos para optimizar el código jugando con la especificidad.

Un saludo y nos vemos en el próximo.

Escribe un comentario

Comentario