CSS :where() y :is(): Especificidad, Resets y Mantenimiento
Muchos desarrolladores ignoran las pseudo-clases CSS :where() e :is(), viéndolas como "azúcar sintáctico". Este artículo revela cómo son cruciales para resolver el caos de la especificidad, permitiendo crear CSS escalable y mantenible. Entiende la diferencia y aplícala en resets, componentes y sistemas de diseño.

¿Ya has escrito el mismo bloque de CSS tres veces solo cambiando el selector? Ese es exactamente el problema que
:is()y:where()resuelven — y la diferencia entre ambos es más importante de lo que parece.
Este CSS te resulta familiar:
header a,footer a,nav a { color: blue; text-decoration: none;}Repitiendo la misma regla para tres contextos diferentes. Ahora imagina que tienes diez contextos. Y que cada uno tiene tres variaciones de estado — :hover, :focus, :visited. El archivo CSS se convierte en una guía telefónica.
El CSS moderno tiene una respuesta para esto. Dos, de hecho — y parecen iguales pero se comportan diferente en un detalle que te salvará de errores sutiles.
:is() — agrupa selectores sin repetición
El :is() acepta una lista de selectores y aplica el estilo a cualquiera que coincida. El bloque anterior se convierte en:
:is(header, footer, nav) a { color: blue; text-decoration: none;}Una línea, mismo resultado. El navegador lo interpreta exactamente como la versión repetida — semánticamente son equivalentes.
Se vuelve más interesante cuando lo combinas con pseudo-clases:
/* Antes — repetindo pra cada estado */button:hover,button:focus,button:active { background: darkblue;}/* Depois — limpo */button:is(:hover, :focus, :active) { background: darkblue;}O para estilizar encabezados de una vez:
/* Todos os headings dentro de article */article :is(h1, h2, h3, h4) { font-family: Georgia, serif; line-height: 1.3;}:where() — idéntico, pero sin peso de especificidad
Aquí reside la diferencia importante.
La especificidad en CSS es el sistema de puntuación que decide qué regla prevalece cuando dos se contradicen. Un selector de ID vale más que una clase, que vale más que una etiqueta. Cuando usas :is(), la especificidad del selector más fuerte dentro de los paréntesis se propaga a toda la regla.
/* :is() herda a especificidade do #header — alta */:is(#header, .nav, footer) a { color: blue;}/* ↑ esse seletor tem especificidade de ID por causa do #header, mesmo que o elemento seja .nav ou footer */El :where() funciona igual en comportamiento — pero tiene especificidad cero. Siempre. No importa lo que pongas dentro.
/* :where() — especificidade zero */:where(#header, .nav, footer) a { color: blue;}/* ↑ fácil de sobrescrever — qualquer seletor de classe ou tag já ganha */En la práctica, esto significa que :where() es ideal para estilos base y resets — defines sin bloquear al desarrollador que personalizará después.
La diferencia en la vida real
/* base.css */:is(article, section) p { color: gray;}/* theme.css — não vai funcionar */p { color: black;}/* :is(article, section) p tem especificidade maior que p *//* base.css */:where(article, section) p { color: gray;}/* theme.css — funciona */p { color: black;}/* :where() tem especificidade zero qualquer p ganha na sobreposição */Un ejemplo que une ambos
En un sistema de diseño, usarías ambos en capas diferentes:
/* Camada base — :where() pra não travar ninguém */:where(h1, h2, h3, h4, h5, h6) { margin: 0 0 0.5em; line-height: 1.2;}/* Camada de componente — :is() pra contextos específicos */.card :is(h2, h3) { font-size: 1.25rem; color: var(--color-heading);}/* Estados interativos — :is() porque precisa de peso */.btn:is(:hover, :focus-visible) { outline: 2px solid currentColor; outline-offset: 2px;}

