El colapso de márgenes y sus tres casos
Por qué dos márgenes contiguos se funden en uno, cómo se calcula el resultado cuando hay negativos, los tres casos exactos en que ocurre y por qué el del padre parece un bug y no lo es.
Dos bloques con margin-block: 1rem no se separan 2rem: se separan 1rem. Un contenedor sin borde no contiene el margen superior de su primer hijo, lo expulsa hacia arriba y se lo queda para sí. Un div vacío con márgenes arriba y abajo no ocupa la suma de los dos. Los tres comportamientos parecen tres rarezas independientes y son la misma regla vista desde tres ángulos.
- Explicar por qué el colapso existe y qué problema tipográfico resuelve.
- Calcular el margen resultante cuando hay valores positivos y negativos.
- Identificar los tres casos de colapso y reconocerlos en el inspector.
- Entender el caso padre-hijo sin recurrir a “es un bug de CSS”.
Por qué existe el colapso
El colapso solo ocurre en el eje de bloque —el vertical en un modo de escritura horizontal— y solo entre cajas que participan en el mismo flujo normal. Nunca entre márgenes horizontales, nunca en flex, nunca en grid.
La razón es tipográfica y sale directamente del problema que CSS venía a resolver en 1996: maquetar documentos. Si un párrafo declara margin: 1em 0 y el siguiente lo mismo, lo que quieres entre ellos es una línea en blanco, no dos. Si un h2 declara margin-block-end: 0.5em y el párrafo que le sigue declara margin-block-start: 1em, lo que quieres es el mayor de los dos, porque cada uno está expresando la separación mínima que necesita y satisfacer la mayor satisface también la menor.
Sin colapso, cualquier documento acumularía el espacio de cada pareja de elementos y el ritmo vertical sería imposible de controlar sin poner a cero la mitad de los márgenes. Con colapso, cada elemento declara lo que necesita y el motor resuelve el conjunto.
Esa es la clave que hay que llevarse: un margen no declara un espacio que se añade, declara una separación mínima que se exige. Dos exigencias sobre el mismo hueco se satisfacen con una sola separación.
La aritmética del margen resultante
Cuando dos o más márgenes colapsan, el valor resultante se calcula así:
Si todos son positivos, gana el mayor.
/* 20px y 30px colapsan en 30px. */
.a { margin-block-end: 20px; }
.b { margin-block-start: 30px; }
Si todos son negativos, gana el más negativo.
/* -10px y -25px colapsan en -25px. */
Si hay de los dos signos, se suma el mayor positivo con el más negativo.
/* 30px y -10px colapsan en 20px. */
/* 30px, 10px y -25px colapsan en 30 + (-25) = 5px. */
Es decir: el máximo de los positivos más el mínimo de los negativos. Ningún otro valor interviene, aunque haya cinco márgenes en juego.
Los tres casos
flowchart TB subgraph C1[Caso 1 hermanos adyacentes] A1[Margen inferior del primero] --> A2[Se funden en uno] A3[Margen superior del segundo] --> A2 end subgraph C2[Caso 2 padre e hijo] B1[Margen superior del padre] --> B2[Salen juntos por fuera del padre] B3[Margen superior del primer hijo] --> B2 end subgraph C3[Caso 3 caja vacia] D1[Margen superior propio] --> D2[Se funden entre si] D3[Margen inferior propio] --> D2 end style A2 fill:#89b4fa,color:#11111b style B2 fill:#f9e2af,color:#11111b style D2 fill:#cba6f7,color:#11111b
Caso 1: hermanos adyacentes. El margen inferior de un bloque y el superior del siguiente colapsan. Es el caso amable y el que todo el mundo espera.
<p>Primero</p>
<p>Segundo</p>
p { margin-block: 1rem; }
/* Separacion entre los dos parrafos: 1rem, no 2rem. */
Caso 2: padre e hijo. El margen superior de un padre colapsa con el de su primer hijo si no hay nada entre ellos, y el resultado se aplica por fuera del padre. Lo mismo ocurre con el margen inferior y el último hijo.
<div class="tarjeta">
<h2>Titulo</h2>
</div>
.tarjeta { background: canvas; } /* sin borde ni relleno */
.tarjeta h2 { margin-block-start: 2rem; }
/* El 2rem NO queda dentro de la tarjeta: empuja la tarjeta entera hacia abajo. */
Aquí es donde aparece el síntoma clásico: el fondo de la tarjeta empieza justo en el título, el espacio queda por encima del fondo, y parece que el margen se ha “escapado”. No se ha escapado: es que padre e hijo comparten la misma arista superior y por tanto el mismo hueco.
Caso 3: caja vacía. Un bloque sin contenido, sin relleno, sin borde y sin altura no tiene interior que separe su arista superior de la inferior, así que sus propios dos márgenes colapsan entre sí.
<div class="separador"></div>
.separador { margin-block: 1rem; }
/* Ocupa 1rem en total, no 2rem. */
Y aquí está el efecto compuesto que hay que conocer: una caja que colapsa a través de sí misma deja de separar a sus vecinos, así que su margen resultante colapsa a su vez con el de los hermanos de alrededor. Una fila de tres divs vacíos con margin-block: 1rem produce 1rem de separación total, no 6rem. El colapso encadena.
Cuando un margen colapsa, las herramientas de desarrollo siguen mostrando el valor declarado en el diagrama de caja de cada elemento, porque ese es el valor calculado y sigue siendo correcto. Lo que no se ve es el resultado del colapso. La pista fiable es medir la distancia real entre las dos cajas y compararla con la suma de lo declarado: si es menor, hay colapso. Y para el caso padre-hijo, el indicio inequívoco es que el resaltado del padre al pasar el ratón empieza más abajo de lo que esperabas y su margen superior coincide con el del hijo.
Por qué el caso del padre parece un bug
Porque contradice una intuición muy razonable: si algo está dentro de otra cosa, su espacio debería estar dentro también. Pero esa intuición se aplica al relleno, que sí es parte del elemento, y no al margen, que no lo es.
Piénsalo con la definición de arriba. El margen superior del hijo exige una separación mínima entre su arista superior y lo que haya antes. Si el padre no tiene borde ni relleno ni contenido en línea, entre la arista superior del padre y la del hijo no hay nada: son la misma línea. Y una exigencia de separación sobre esa línea es una exigencia sobre lo que hay antes del padre, no sobre el interior del padre, porque el interior del padre empieza exactamente ahí.
Visto así, el caso 2 no es una excepción del caso 1: es el caso 1 aplicado a dos aristas que resultan coincidir. Y el caso 3 es el mismo otra vez, con las dos aristas de un mismo elemento.
Lo que corta el colapso y por qué lo verás en la lección siguiente. La versión corta es que basta con que aparezca cualquier cosa entre las dos aristas —un borde, un relleno, contenido— o con que el padre deje de participar en el mismo contexto de flujo. Ese segundo mecanismo, el de los contextos de formato, se estudia a fondo en el catálogo del BFC, y explica también por qué el problema desaparece en cuanto el padre es flex o grid.
Los tres casos se memorizan mal porque se enseñan como tres reglas. Son una sola, y se enuncia así: un margen no es una propiedad del elemento sino una exigencia sobre una arista, y cuando varias exigencias caen sobre la misma arista solo se satisface una separación. Con esa formulación, los tres casos se derivan sin esfuerzo. Dos hermanos comparten la arista que hay entre ellos, luego sus márgenes contiguos hablan del mismo hueco y se funden. Un padre sin borde ni relleno comparte su arista superior con la de su primer hijo, luego los dos márgenes hablan del mismo hueco —el que hay antes del padre— y se funden ahí. Una caja vacía tiene su arista superior y su inferior en el mismo sitio, luego sus dos márgenes hablan del mismo hueco y se funden. No hay tres reglas: hay una definición de qué es un margen que nunca nos contaron bien. Y la reformulación tiene una consecuencia de diseño que va mucho más allá del colapso, porque explica por qué los márgenes son problemáticos en componentes: un margen es información sobre una relación, y un componente no conoce sus relaciones. Cuando escribes margin-block-end: 1rem en una tarjeta estás afirmando algo sobre lo que vendrá después, que es precisamente lo único que la tarjeta no puede saber. De ahí sale el consejo, tan repetido como mal justificado, de que los componentes no lleven márgenes exteriores: no es una convención estética, es que un componente no está en posición de declarar una propiedad que describe su vecindad. La separación entre hermanos le corresponde al contenedor, que sí conoce a ambos. Y esa es exactamente la razón de que exista gap.
- Monta dos párrafos con márgenes distintos y comprueba que la separación es el mayor.
- Suma un margen positivo y uno negativo y verifica la aritmética.
- Reproduce el caso padre-hijo y localiza en el inspector dónde empieza el fondo del padre.
- Encadena tres divs vacíos con márgenes y mide la separación total.
- Explica el caso 3 usando únicamente la definición de margen como exigencia sobre una arista.