auto no es un valor: es una incógnita
Qué significa exactamente la palabra auto en cada propiedad, cómo se cuentan las incógnitas de la ecuación del flujo y por qué no puedes hacer aritmética ni animar con ella.
auto es la palabra más usada de CSS y la peor entendida. No es un valor por defecto ni un sinónimo de “lo normal”: es una marca que dice esta cifra no la pongo yo, la resuelve el algoritmo, y el algoritmo al que llama es distinto en cada propiedad. Saber leer un auto como una incógnita en una ecuación, y no como un valor concreto, es lo que convierte el dimensionado de CSS en algo predecible.
- Leer cualquier
autoidentificando qué algoritmo delega y sobre qué eje. - Contar las incógnitas de la ecuación del flujo y predecir el reparto resultante.
- Aplicar
autoen márgenes y eninsetpara posicionar sin números mágicos. - Justificar por qué
autono se puede usar encalc()ni interpolar en una animación.
La misma palabra, algoritmos distintos
La confusión empieza porque auto aparece en propiedades que no tienen nada que ver entre sí. No hay un comportamiento “auto”: hay una convención de escritura que significa delego, y el destinatario de la delegación cambia.
| Declaración | A qué algoritmo delega | Resultado típico |
|---|---|---|
inline-size: auto |
Resolución de anchos del flujo | Llena el contenedor |
block-size: auto |
Altura por contenido | Abraza el contenido |
margin-inline: auto |
Reparto del sobrante de la ecuación | Centra |
inset-inline-start: auto |
Posición estática del elemento | Donde habría estado sin posicionar |
overflow: auto |
Decisión de barra de desplazamiento | Barra solo si hace falta |
cursor: auto |
Decisión del navegador según el contenido | Flecha o cursor de texto |
Las dos últimas filas no son dimensionado en absoluto, y sin embargo comparten palabra. Por eso la pregunta correcta ante cualquier auto nunca es “¿qué valor es?” sino “¿auto según qué algoritmo?”. En cuanto te acostumbras a formularla, las sorpresas caen mucho.
Hay además una propiedad decisiva de auto que se deduce de lo anterior: no se resuelve en el momento de calcular valores, sino en el momento de usarlos. El valor calculado de width: auto sigue siendo auto; solo durante el layout, cuando ya se conoce el bloque contenedor, se convierte en un número de píxeles. Esa demora es exactamente lo que permite que una caja se adapte, y también lo que causa el fallo del height en porcentaje de la lección anterior: si el valor con el que quieres calcular todavía es auto, no hay número contra el que aplicar el porcentaje.
Contar incógnitas en el flujo
La ecuación de anchos del flujo normal tiene tres términos que pueden ser incógnitas: el margen de inicio, el ancho y el margen de final. Todo lo demás —bordes y rellenos— es siempre conocido. El comportamiento resultante depende solo de cuántos de los tres son auto, y la tabla completa cabe en cinco filas.
| Incógnitas | Qué hace el motor |
|---|---|
| Ninguna, y la suma no cuadra | Ignora el margen final y le asigna el sobrante |
| Solo el ancho | El ancho absorbe todo el sobrante |
| Solo un margen | Ese margen absorbe todo el sobrante |
| Los dos márgenes | El sobrante se reparte a partes iguales: centrado |
| Ancho y algún margen | Los márgenes auto valen cero y el ancho absorbe el resto |
La última fila explica un fallo clásico. Esto no centra nada:
/* El ancho ya es auto: no hay sobrante que repartir */
.caja { margin-inline: auto; }
Con inline-size: auto la caja ya ocupa todo el ancho disponible, el sobrante vale cero, y los márgenes auto se resuelven a cero. Centrar exige que la caja sea más estrecha que su contenedor, es decir, que el ancho deje de ser incógnita:
.caja {
inline-size: min(65ch, 100%);
margin-inline: auto;
}
Ahí sí hay sobrante, y ahí sí se reparte. La versión con min() es además la forma robusta de escribirlo: fija un ancho de lectura cómodo, pero nunca supera el contenedor, así que no desborda en pantallas estrechas.
El mismo juego de incógnitas funciona con elementos posicionados, y da el otro centrado clásico. En posicionamiento absoluto la ecuación incluye inset-inline-start, el ancho y inset-inline-end; si fijas los dos extremos y dejas ancho y márgenes como incógnitas, el reparto vuelve a producir centrado en los dos ejes:
.superpuesto {
position: absolute;
inset: 0;
inline-size: 20rem;
block-size: 12rem;
margin: auto;
}
No hay transform, no hay 50% ni resta de la mitad: solo una ecuación con dos incógnitas simétricas. Y a diferencia del truco con translate, esta versión no puede producir medios píxeles ni texto borroso, porque el reparto lo hace el layout y no una transformación posterior.
Hay una asimetría fea en el diseño del lenguaje que conviene tener localizada. En casi todas partes auto significa “delego en el algoritmo” y se resuelve tarde, durante el layout. Pero en las propiedades de mínimo automático de los contextos de layout modernos, auto significa otra cosa: un valor concreto calculado a partir del contenido, que existe para impedir que un elemento se encoja por debajo de lo que su contenido necesita. Esa diferencia produce el bug más reportado de Flexbox y de Grid: un elemento con un texto largo, o con un hijo que tiene su propia barra de desplazamiento, se niega a encogerse y desborda el contenedor por más inline-size pequeño que le pongas. La causa no es el ancho que declaraste, es un mínimo que no declaraste tú y que sigue vigente. El diagnóstico es reconocible al instante: el elemento mide exactamente lo que mide su contenido más largo y ninguna propiedad de ancho lo mueve. La cura es declarar explícitamente el mínimo que quieres, típicamente min-inline-size: 0 en el eje que corresponda, o overflow distinto de visible en el hijo, que también desactiva ese mínimo automático. Y la lección general, que va más allá del bug concreto: cuando un elemento se resiste a un tamaño, busca la restricción de mínimo antes que la de tamaño, porque los mínimos ganan siempre y muchos están puestos por defecto sin que aparezcan escritos en ningún sitio.
Lo que no puedes hacer con una incógnita
De la naturaleza de auto se siguen tres limitaciones duras, y las tres se topan antes o después.
No puedes meterlo en calc(). calc(100% - auto) no es válido y la declaración entera se descarta en silencio. La razón es directa: calc() opera sobre valores numéricos con unidades, y auto no es un número, es una instrucción de delegación. Cuando te descubres queriendo restar un auto, lo que necesitas casi siempre es que el propio algoritmo haga el reparto —un margen auto, un fr en Grid, un flex-grow— en lugar de calcularlo tú.
No puedes interpolarlo. Animar de block-size: 0 a block-size: auto no funciona, y nunca ha funcionado, porque una transición necesita dos números entre los que interpolar y en un extremo no hay número. Ese es el motivo real de que la técnica habitual para desplegables sea animar max-block-size entre dos valores concretos, o grid-template-rows entre 0fr y 1fr, que sí son cantidades interpolables:
.desplegable {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 250ms ease;
}
.desplegable[open] { grid-template-rows: 1fr; }
.desplegable > * { overflow: hidden; }
No puedes leerlo esperando un número consistente. Preguntar por el valor calculado de una propiedad que sigue siendo auto te devuelve auto en unas propiedades y una resolución en píxeles en otras, según si el navegador expone el valor calculado o el usado. Si necesitas la geometría real, pídela con las APIs de geometría y no con los estilos.
La conclusión operativa es corta: auto es una herramienta de diseño, no un dato. Sirve para dejarle trabajo al motor, que es lo que quieres en el noventa por ciento de los casos. En cuanto necesitas operar con una cifra, tu diseño te está pidiendo un valor definido, y forzar auto en ese punto es empujar el problema a otro lado.