wandres.dev
DIMENSIONAR · Tamaños intrínsecos y extrínsecos

min-content y max-content: cómo se calculan de verdad

Las dos medidas intrínsecas fundamentales, el algoritmo exacto con el que el motor las obtiene, cómo se propagan hacia arriba desde los descendientes y qué las falsea.

⏱ 19 min

min-content y max-content no son estimaciones ni aproximaciones: son dos números que el motor calcula con un algoritmo definido y que sirven de entrada a casi todo lo demás. La resolución de una pista de grid, el tamaño base de un elemento flex, el ancho de una celda de tabla y el ajuste de un flotante son todos funciones de este par. Entenderlos bien es entender de dónde salen los números que ves en las DevTools.

🎯 Al terminar esta lección sabrás
  • Calcular a mano el min-content y el max-content de un contenido dado.
  • Explicar la contribución intrínseca de un hijo al tamaño de su padre.
  • Identificar qué propiedades falsean o congelan estas medidas.
  • Usar min-content para resolver el desbordamiento de contenido no partible.

Las dos medidas

El tamaño max-content de una caja es el ancho que tendría si dispusiera de espacio infinito: todo el contenido en una sola línea, sin ningún salto salvo los que estén escritos explícitamente. Para un párrafo, es la longitud total del texto. Para un contenedor de bloques apilados, es el mayor de los max-content de sus hijos.

El tamaño min-content es el ancho más estrecho posible sin que el contenido desborde: cada oportunidad de salto de línea aprovechada. Para un párrafo de prosa, es la anchura de la palabra más larga. Para un contenedor de bloques, es el mayor de los min-content de sus hijos.

.medida { inline-size: max-content; border: 1px solid; }
<p class="medida">El submarino amarillo</p>

Con max-content, la caja mide lo que ocupa la frase entera en una línea. Con min-content, mide lo que ocupa submarino, la palabra más larga. Los dos números son propiedades del contenido y de la tipografía, y no dependen en absoluto del contenedor.

📝
Las oportunidades de salto no son solo espacios

min-content respeta las mismas reglas de partición que el motor de línea: espacios, guiones, saltos suaves con &shy;, y los puntos de ruptura de los sistemas de escritura CJK, donde casi cada carácter es una oportunidad. Si activas hyphens: auto con el idioma declarado en lang, el min-content de un párrafo puede caer hasta una sílaba.

Cómo se propagan hacia arriba

Lo interesante no es la medida de una caja aislada, sino cómo se combina en un árbol. La especificación define la contribución intrínseca de un hijo: el tamaño que ese hijo aporta al cálculo intrínseco del padre, ya sumados sus márgenes, bordes y rellenos, y ya aplicados sus propios min-inline-size y max-inline-size.

Las reglas de composición dependen del contexto de formato del padre:

contexto del padre max-content del padre min-content del padre
bloques apilados el máximo de las contribuciones el máximo de las contribuciones
línea la suma de las contribuciones el máximo de las contribuciones
flex en fila la suma de las contribuciones depende de shrink y del mínimo automático
grid suma de las pistas resueltas más gaps suma de las pistas resueltas más gaps

La fila de bloques y la de línea explican por sí solas un montón de comportamientos. Un div con tres párrafos tiene el max-content del párrafo más ancho, porque los bloques se apilan y no compiten por el ancho. Un div con tres span tiene el max-content de los tres sumados, porque compiten en la misma línea.

<div class="apilado"><p>Uno</p><p>Dos largo largo</p></div>
<div class="enlinea"><span>Uno</span><span>Dos largo largo</span></div>
.apilado, .enlinea { inline-size: max-content; outline: 1px solid #f38ba8; }

El primero mide lo que mide “Dos largo largo”. El segundo mide “UnoDos largo largo”. Misma propiedad, resultados distintos, y la diferencia está en el contexto de formato, no en el tamaño solicitado.

Qué falsea la medida

Hay tres cosas que rompen la intuición sobre estas medidas, y las tres aparecen en código real constantemente.

La primera es el contenido no partible. Una URL larga sin espacios, una cadena de identificador, un bloque de código con una línea muy larga, una tabla: todos ellos tienen un min-content gigantesco, porque no hay ninguna oportunidad de salto. Cuando ese min-content sube por el árbol, arrastra a sus ancestros y acaba ensanchando la página entera. Es la causa número uno de scroll horizontal accidental.

/* Permite partir palabras solo cuando no queda más remedio */
.contenido { overflow-wrap: break-word; }

/* Para URLs y rutas: parte por cualquier sitio */
.url { word-break: break-all; }

/* Para bloques de código: no partas, haz scroll */
pre { overflow-x: auto; }

overflow-wrap: break-word es la opción correcta por defecto en contenido de usuario: solo actúa cuando una palabra individual no cabe, y no destroza la partición normal.

La segunda es que un porcentaje se comporta como auto durante el cálculo intrínseco. Si un hijo tiene inline-size: 50% y el padre está midiendo su max-content, el padre todavía no tiene ancho, así que el porcentaje no se puede resolver. La especificación dice que en ese caso el porcentaje se trata como auto para el cálculo. Esto produce ciclos aparentes que el motor rompe por regla, y es por lo que un hijo con porcentaje dentro de un padre intrínseco casi nunca hace lo que esperas.

La tercera es que las imágenes con relación de aspecto contribuyen con su tamaño intrínseco real. Una imagen de 4000 píxeles de ancho sin max-inline-size inyecta 4000 píxeles en la cadena de max-content de todos sus ancestros. De ahí que la regla más rentable de cualquier hoja de estilos sea esta:

img, video, svg, canvas { max-inline-size: 100%; block-size: auto; }

Usar min-content a propósito

Más allá de diagnosticar, estas palabras clave resuelven problemas concretos.

Un caso: una barra lateral que debe ser tan estrecha como su contenido permita, sin fijar un número arbitrario.

.disposicion {
  display: grid;
  grid-template-columns: min-content 1fr;
  gap: 1.5rem;
}

Otro caso: un título que debe partirse de forma equilibrada pero no ocupar más de lo necesario. max-content como ancho y text-wrap: balance para el reparto.

.titular {
  inline-size: min(max-content, 100%);
  text-wrap: balance;
}

La función min() con 100% es el detalle importante: max-content por sí solo desborda alegremente el contenedor si el texto es largo, porque es intrínseco y no mira al padre. Combinarlo con un tope extrínseco es el patrón que hace que el resultado sea seguro.

El sizing intrínseco cuesta dinero, y por eso existen containment y las container queries

Hay una razón de ingeniería, no de diseño, para que estas medidas te importen: calcularlas es caro. Obtener el max-content de una caja exige medir todo su subárbol, y el min-content exige además probar cada oportunidad de salto. Peor aún, esas medidas viajan hacia arriba: un cambio en una palabra del último nodo puede alterar el ancho de un ancestro a diez niveles de distancia, lo que obliga al motor a rehacer el layout de una rama entera. Ese acoplamiento vertical es exactamente el problema que contain vino a resolver: contain: size es una promesa de que el tamaño de la caja no depende de su contenido, y con ella el motor puede maquetar el interior sin volver a subir. Y aquí está la conexión que casi nadie ve: las container queries existen gracias a esa promesa. Consultar el tamaño de un contenedor para estilar su contenido sería una dependencia circular —el contenido determina el tamaño, el tamaño determina el contenido— si el contenedor no renunciara antes a dimensionarse por su contenido en el eje consultado. Por eso container-type: inline-size aplica containment de tamaño en el eje en línea, que es justo el eje que luego se consulta, y por eso no existe una consulta de altura sin declarar container-type: size con todas sus consecuencias. Toda la familia de layout moderno se apoya en decidir dónde se corta la propagación intrínseca.