Kodokon kodokon.com

Selectores modernos: :has, :is, :where, :nth-child avanzado

Aprovecha las pseudoclases funcionales recientes para seleccionar según el contenido, agrupar selectores sin inflar la especificidad y apuntar a patrones complejos.

9 min · 3 preguntas

Abrir esta lección en Kodokon

:is() y :where() agrupan selectores, pero divergen en un punto decisivo: la especificidad. :is(nav, .menu, #main a) toma la especificidad de su argumento más fuerte (aquí el ID), aunque sea nav el que coincida. :where() tiene una especificidad de cero, sean cuales sean sus argumentos. Consecuencia práctica: :where() es la herramienta ideal para los reinicios y los estilos por defecto de un sistema de diseño, que cualquier selector de clase simple podrá luego sobrescribir sin pelea.

CSS
:where(h1, h2, h3, h4) {
  margin-block: 0;
  line-height: 1.2;
}

:is(article, aside, section) :is(h2, h3) {
  font-family: var(--font-heading);
}

.prose :is(ul, ol) li + li {
  margin-top: 0.5em;
}
Agrupar y controlar la especificidad

:has() por fin invierte el sentido de lectura: el selector apunta a el elemento anfitrión, no a lo que contiene. .card:has(> img) selecciona la tarjeta que tiene una imagen como hijo directo. Combinado con las pseudoclases de estado, permite que la información fluya hacia arriba sin JavaScript: dar estilo a una etiqueta cuando su campo es inválido, a un formulario cuando un campo tiene el foco, a una fila de tabla cuando su casilla está marcada.

CSS
.field:has(input:invalid:not(:focus)) label {
  color: #dc2626;
}

.card:has(> img) {
  padding-top: 0;
}

tr:has(input[type="checkbox"]:checked) {
  background: #eef2ff;
}
Seleccionar según el contenido o el estado interno

Sobre :nth-child(), dos habilidades que consolidar. Primero, leer las fórmulas An+B: 2n (pares), 2n+1 (impares), -n+3 (los tres primeros), n+4 (del cuarto al final); el rango "del 2.º al 5.º" se escribe combinando :nth-child(n+2):nth-child(-n+5). Segundo, la sintaxis más reciente of S: :nth-child(2n of .visible) cuenta solo entre los hijos que coinciden con .visible, mientras que .visible:nth-child(2n) cuenta todos los hijos y luego filtra - dos resultados muy distintos en cuanto se intercalan otros elementos.

CSS
tr:nth-child(odd) {
  background: #fafafa;
}

li:nth-child(-n + 3) {
  font-weight: 600;
}

li:nth-child(n + 2):nth-child(-n + 5) {
  border-top: 1px solid #e5e7eb;
}

.row:nth-child(2n of .visible) {
  background: #eef2ff;
}
Fórmulas An+B y la sintaxis of S

Prueba de conocimientos

Comprueba que has retenido los puntos clave de esta lección.

  1. ¿Cuál es la especificidad de :where(#main, .nav, a)?
    • La del ID, es decir (1,0,0)
    • La suma de los tres argumentos
    • Cero, sean cuales sean los argumentos
    • La del argumento que realmente coincide
  2. ¿Qué selecciona .card:has(> img)?
    • Las imágenes que son hijas directas de una tarjeta
    • Las tarjetas que contienen una imagen como hijo directo
    • Las tarjetas situadas después de una imagen en el DOM
    • Todas las imágenes que son descendientes de tarjetas
  3. En una lista donde solo algunos elementos li llevan .visible, ¿qué hace li:nth-child(2n of .visible)?
    • Apunta a los elementos li pares de la lista que además tienen la clase .visible
    • Apunta a uno de cada dos li, contando solo los elementos li.visible
    • Apunta a los elementos li pares y luego les añade la clase .visible