Qué resuelve CSS y qué deja deliberadamente fuera
El encargo original del lenguaje —dar formato a un documento que se verá en un dispositivo desconocido, por un usuario con necesidades desconocidas— y las consecuencias de diseño que arrastra hasta hoy.
Casi todas las quejas sobre CSS son quejas sobre decisiones que se tomaron a propósito. La tolerancia a errores, la existencia de tres hojas de estilo compitiendo, el hecho de que el usuario pueda ganarte una discusión de estilos: nada de eso es descuido histórico, es el encargo. CSS se diseñó para dar formato a documentos que se verán en un dispositivo que no conoces, con un tamaño que no controlas, por una persona cuyas necesidades no puedes anticipar. Entender ese encargo explica por qué el lenguaje es como es, y por qué las herramientas que lo ignoran acaban peleándose con él.
- Enunciar el problema que CSS resuelve y las tres incógnitas que asume de partida.
- Distinguir los tres orígenes de estilo y el papel que juega cada uno.
- Justificar la tolerancia a errores del parser como decisión de diseño, no como defecto.
- Delimitar qué problemas no son de CSS y por qué conviene no forzarlos.
El encargo: dar formato a lo desconocido
Un lenguaje de maquetación de imprenta trabaja con certezas. Sabe el tamaño de la página, sabe la tinta, sabe que nadie va a ampliar el cuerpo de letra a mitad de lectura. CSS no tiene ninguna de esas certezas y nunca las tuvo. Se le pidió describir la presentación de un documento sin saber tres cosas fundamentales, y todo el diseño del lenguaje es la consecuencia de esa ignorancia asumida.
No sabe el medio. El mismo documento puede acabar en una pantalla de 4K, en un móvil en vertical, en un lector de pantalla que no dibuja nada, en una impresora o en un navegador de texto. Por eso las unidades relativas son ciudadanas de primera clase y las absolutas son la excepción, y por eso el lenguaje distingue entre lo que quieres y lo que se puede.
No sabe el contenido exacto. Una tarjeta puede llevar un título de tres palabras o de veinte. Un menú puede tener cuatro elementos hoy y once mañana. De ahí que el dimensionado por defecto sea automático y que los algoritmos de layout modernos —Flexbox, Grid con minmax, fit-content— estén construidos alrededor de la idea de que el contenido tiene voz en su propio tamaño.
No sabe el usuario. Puede tener baja visión y necesitar el texto al doble, puede haber pedido menos movimiento porque las animaciones le provocan mareo, puede preferir contraste alto o esquema oscuro. CSS le da mecanismos reales para imponer sus preferencias, y le da al autor mecanismos para consultarlas y respetarlas por adelantado.
De esas tres incógnitas sale una regla práctica que vale para toda la guía: cada vez que fijas un valor absoluto estás apostando contra una de las tres. A veces la apuesta es razonable. Pero conviene saber que estás apostando.
Tres orígenes que compiten, y por qué
La consecuencia estructural más visible del encargo es que en cualquier página hay estilos de tres procedencias distintas, y el lenguaje define quién gana en cada caso. No es un accidente de implementación: está escrito en la especificación de la cascada.
| Origen | Quién lo escribe | Para qué existe |
|---|---|---|
| User agent | El navegador | Que un documento sin CSS siga siendo legible |
| User | La persona que lee | Que pueda imponer necesidades propias |
| Author | Tú | La presentación que diseña el sitio |
El orden normal de prioridad va del autor hacia abajo: tus estilos vencen a los del usuario, y los del usuario vencen a los del navegador. Pero cuando entra !important el orden se invierte, y entonces una declaración importante del usuario vence a una declaración importante tuya, y una del navegador las vence a las dos. Esa inversión es exactamente el mecanismo que garantiza que alguien con baja visión pueda forzar un tamaño mínimo de texto aunque el sitio insista en lo contrario. !important no se diseñó para que ganes discusiones contigo mismo: se diseñó para que el usuario pueda ganártelas a ti.
La hoja del navegador merece una mención aparte porque se subestima. Todo lo que da por hecho —que un h1 es grande y en negrita, que una lista lleva viñetas, que un enlace se subraya, que un botón tiene un aspecto pulsable— viene de ahí. No es un estorbo que haya que borrar de un plumazo: es una capa de significado por defecto que existe para que un documento sin estilos de autor siga funcionando. Una parte importante de la arquitectura CSS moderna consiste en decidir con precisión qué le quitas y qué le respetas.
Cuando el motor encuentra una declaración que no comprende —una propiedad inexistente, un valor mal escrito, una unidad de un módulo que ese navegador aún no soporta— la descarta en silencio y sigue. Ni un error, ni una regla rota, ni el resto de la hoja tirado a la basura. Esa decisión, que a un ingeniero acostumbrado a compiladores le parece una aberración, es lo que ha permitido que la web evolucione durante treinta años sin romper hacia atrás: puedes escribir hoy una propiedad que existirá dentro de dos años y los navegadores actuales simplemente la ignorarán, mientras que los futuros la usarán. El descarte es además granular por declaración, no por regla, lo que convierte el patrón de fallback en algo trivial: escribes primero la versión conservadora y después la moderna, y cada motor se queda con la última que entiende. Este comportamiento se extiende con matices a los selectores: en una lista de selectores clásica, uno inválido invalida la regla entera, y por eso :is() y :where() con sus listas tolerantes son mucho más que azúcar sintáctico. Y tiene un corolario incómodo que conviene interiorizar cuanto antes: si te equivocas al escribir una propiedad, CSS no te va a avisar. No hay compilador que te salve. El coste de la resiliencia lo pagas tú en depuración.
Lo que ya no hay que hacer con JavaScript
La frontera entre CSS y JavaScript no es fija: se ha movido mucho, y siempre en la misma dirección. Cosas que en 2020 exigían un ResizeObserver, un MutationObserver o una biblioteca de posicionamiento hoy son declarativas. El criterio que separa ambos mundos en 2026 es razonablemente nítido: si el estilo depende solo de la estructura del documento, del estado del propio elemento o de las dimensiones de su contenedor, es trabajo de CSS. Si depende de datos de la aplicación, de peticiones de red o de decisiones de negocio, es trabajo de JavaScript.
Bajo ese criterio, media docena de patrones han cambiado de bando:
- Estilar un contenedor según lo que contiene ya no necesita una clase puesta desde JavaScript, porque existe el selector relacional
:has(). - Adaptar un componente a su espacio disponible ya no necesita observar tamaños, porque existen las container queries.
- Colocar un tooltip junto a su disparador y reubicarlo cuando no cabe ya no necesita una biblioteca de posicionamiento: el anclaje nativo entró en Baseline cuando Firefox lo implementó en enero de 2026, con la reserva de que
@position-tryexige Safari 18.4 o superior. - Un diálogo modal con foco atrapado y fondo inerte es un elemento
dialog, y un menú que se cierra al pulsar fuera es el atributopopover.
Lo que sigue siendo de JavaScript también conviene tenerlo claro, porque intentar meterlo en CSS produce monstruos. CSS no sabe leer datos, no sabe pedir nada al servidor, no tiene estructuras de control ni variables mutables en el sentido de un lenguaje imperativo, y no debe usarse como canal de lógica de negocio. Y hay una frontera dura que no se cruza nunca: el orden visual no sustituye al orden del documento. Reordenar cajas con order o colocarlas en celdas de una cuadrícula no cambia el orden de lectura de un lector de pantalla ni el orden de tabulación del teclado. Si el orden importa para entender el contenido, tiene que estar en el HTML.
Qué te llevas de esta lección al resto de la guía
Tres criterios, que reaparecerán constantemente.
El primero: antes de fijar un valor, pregunta contra cuál de las tres incógnitas estás apostando. Si la respuesta es “contra el tamaño del texto del usuario”, casi siempre hay una forma mejor.
El segundo: la hoja del navegador y las preferencias del usuario son parte de tu diseño, no ruido que eliminar. Un reset agresivo que borra indiscriminadamente destruye información útil y suele acabar reimplementada peor.
El tercero: si algo se puede expresar como una condición sobre la estructura, el estado o el espacio, exprésalo en CSS. No por purismo, sino porque el motor lo evalúa en el momento correcto del pipeline y sin coste de sincronización, cosa que ningún observador en JavaScript puede garantizar.