Una declaración es una restricción, no una orden
Por qué el motor puede ignorar legítimamente lo que escribes, qué significa que un sistema de restricciones esté sobredeterminado y de dónde salen las restricciones que tú no pusiste.
Casi todo el mundo aprende CSS como si fuera un lenguaje de órdenes: escribo width: 400px y el elemento mide cuatrocientos píxeles. Ese modelo funciona mientras el ejemplo es simple y se derrumba en cuanto la página se parece a una página real. El modelo correcto es otro: cada declaración es una restricción que entra en un sistema junto a otras que tú no has escrito, y el motor resuelve el sistema entero con reglas fijas. Cuando el resultado no es el que esperabas, casi nunca es porque el motor te ignoró: es porque tu restricción era incompatible con otra y la especificación dice cuál cede.
- Explicar por qué un valor declarado puede no ser el valor con el que se dibuja.
- Reproducir la ecuación de anchos del flujo normal y decir quién cede cuando no cuadra.
- Enumerar las tres procedencias de las restricciones que actúan sobre un elemento.
- Reformular un problema de CSS como una pregunta sobre qué restricción ganó.
El motor no obedece, resuelve
Prueba mental. Tienes un contenedor de 600 píxeles y dentro este elemento:
.contenedor { width: 600px; }
.caja {
width: 400px;
margin-left: 0;
margin-right: 0;
border: 0;
padding: 0;
}
Todo cuadra hasta que te preguntas qué ocupa los 200 píxeles sobrantes. La respuesta de la especificación es precisa y sorprende la primera vez: en el flujo normal, para una caja de bloque no reemplazada, se cumple obligatoriamente esta igualdad:
margin-left + border-left + padding-left + width +
padding-right + border-right + margin-right = ancho del bloque contenedor
No es una recomendación: es una ecuación que el motor tiene que satisfacer sí o sí. Si sustituyes los valores del ejemplo obtienes 0 + 400 + 0 = 600, que es falso. El sistema está sobredeterminado, y en ese caso la regla escrita dice que se ignora el margin-right declarado y se le asigna el valor que haga cierta la igualdad. Tu margin-right: 0 sigue estando en la hoja de estilos, sigue apareciendo en el panel de estilos, y sin embargo el margen que existe de verdad mide 200 píxeles.
Aquí está el cambio de modelo mental completo. No has dado una orden que el motor haya desobedecido. Has añadido una restricción a un sistema que ya tenía otras, el sistema no tenía solución, y hay una regla determinista que decide cuál de las restricciones se sacrifica.
La misma ecuación, leída al revés, explica el truco de centrado más famoso de CSS. Si en lugar de 0 pones auto en los dos márgenes, estás diciendo “estos dos no los fijo yo, resuélvelos tú”, el sistema pasa a tener una única solución con los dos márgenes iguales, y el elemento queda centrado:
.caja {
width: 400px;
margin-inline: auto;
}
Nadie ha programado un “centrar”. Lo que hay es una incógnita repetida dos veces en una ecuación, y la especificación dice que en ese caso se reparte a partes iguales. El centrado es un efecto secundario de resolver el sistema.
Conviene decir con precisión qué clase de solucionador es el motor, porque la palabra restricción evoca sistemas donde hay margen de interpretación y aquí no lo hay. CSS no tiene un solucionador general de restricciones que busque un óptimo: tiene un conjunto de algoritmos concretos, cada uno con su orden de resolución y sus reglas explícitas de desempate, escritos en las especificaciones con el mismo nivel de detalle que un algoritmo de ordenación. Cuando la ecuación de anchos está sobredeterminada, la especificación no dice “el motor decide”, dice literalmente que se ignora el margen del final de la línea según la dirección de escritura. Cuando un elemento flexible no cabe, hay una fórmula exacta de reparto del sobrante o del faltante. La consecuencia práctica es enorme y casi nadie la explota: cualquier comportamiento que te sorprenda tiene una respuesta escrita, y buscarla cuesta menos que probar valores al azar. Y hay un corolario todavía más útil: si dos navegadores dan resultados distintos ante el mismo CSS, no estás ante “los navegadores, que son diferentes”, estás ante un bug de alguno de ellos, reportable y con un test que lo demuestra. Ese cambio de actitud —de resignación a diagnóstico— es exactamente lo que ha hecho posible que el soporte cruzado mejorase tanto desde 2021, porque los tests de interoperabilidad los escribe gente que dejó de aceptar la diferencia como inevitable.
De dónde salen las restricciones que tú no escribiste
Si solo pelearas contra tus propias declaraciones, CSS sería trivial. El sistema tiene tres fuentes, y solo controlas una.
Las que escribes tú. Las declaraciones de tus hojas, más las que hereden de ancestros, más las que aporte cualquier CSS de terceros que hayas cargado. Es la única fuente sobre la que tienes autoridad directa.
Las que impone el contenido. Una caja tiene preferencias intrínsecas de tamaño que salen de lo que lleva dentro: la palabra más larga de un párrafo, el ancho natural de una imagen, la altura acumulada de sus hijos. Estas restricciones no están escritas en ninguna hoja de estilos y sin embargo participan en la resolución con el mismo derecho que las tuyas. Un botón que no baja de cierto ancho por más que le pongas width pequeño no está roto: hay una restricción de contenido que no le permite encogerse tanto.
Las que impone el entorno. El tamaño de la ventana, el tamaño de fuente base que el usuario ha configurado, sus preferencias declaradas de movimiento o contraste, el espacio seguro de un dispositivo con muesca. Aquí la restricción viene de fuera del documento y cambia mientras la página está abierta.
De las tres sale la observación que más ahorra tiempo a largo plazo: cuanto más restringes tú, menos espacio le dejas al motor para absorber lo que cambia. Un layout construido con anchos y alturas fijas no es más controlado, es más frágil, porque cada valor absoluto es una restricción que entrará en conflicto en cuanto el contenido o el entorno se muevan. Un layout construido con rangos —mínimos, máximos, proporciones, clamp()— le da al solucionador margen para encontrar solución en más situaciones. Escribir CSS robusto es, literalmente, restringir lo justo.
Las cuatro preguntas que reformulan cualquier bug
Cuando algo no sale, el instinto es cambiar valores. El método es otro: convertir el síntoma en una pregunta sobre el sistema de restricciones. Cuatro preguntas, en este orden.
¿Llegó siquiera mi declaración? Si perdió la cascada o el selector no casa, no hay restricción que resolver y todo lo demás sobra. Es la pregunta de la cascada.
¿Se aplica esa propiedad a esta caja? Muchas propiedades tienen una línea de “se aplica a” que restringe su efecto a un tipo de caja concreto. gap no hace nada en un contenedor que no sea flex, grid o multicolumna. vertical-align no hace nada sobre una caja de bloque. La declaración está y es válida, pero no participa en ninguna ecuación.
¿Con qué otra restricción choca? Aquí entran los mínimos y máximos, las restricciones de contenido y la ecuación del bloque contenedor. Es donde vive la mayoría de los casos.
¿El bloque contenedor es el que creo? Todos los porcentajes, la ecuación de anchos y el posicionamiento se resuelven contra un bloque contenedor concreto, y no siempre es el padre visual. Equivocarse aquí produce resultados que parecen aleatorios.
Ninguna de las cuatro se contesta cambiando un valor y recargando. Se contestan mirando: la primera en el panel de estilos, la segunda en la documentación de la propiedad, la tercera y la cuarta en el panel de cajas y en el árbol.
Qué cambia en tu forma de escribir
Tres hábitos se siguen directamente de este modelo, y los tres van contra la intuición del que viene de lenguajes imperativos.
Declara intención, no resultado. margin-inline: auto dice “reparte lo que sobre”; margin-left: 100px dice “confía en que el contenedor mide 600”. El primero sobrevive a un cambio de contenedor y el segundo no.
Prefiere rangos a puntos. min-width, max-width, minmax() y clamp() son formas de restringir sin sobredeterminar. Un valor único es una afirmación sobre el futuro; un rango es una condición sobre el resultado.
Deja incógnitas a propósito. Cada auto que dejas es un grado de libertad que el motor usará para absorber lo que no previste. La tentación de fijarlo todo “para tener control” produce exactamente lo contrario: un sistema tan rígido que cualquier cambio lo rompe, y en el que cada arreglo consiste en añadir otra restricción encima.