De forma general, los elementos de un documento HTML se representan como una caja o bloque cuyas características define el llamado box model (modelo de bloques o cajas). Este modelo se aplica de forma predeterminada a todos los elementos de nivel bloque y también a los elementos con las propiedades CSS display: block y display: inline-block.

En esa caja que representa al elemento se pueden diferenciar cuatro zonas que influyen en las medidas del bloque, desde fuera hacia dentro:

  1. Margen
  2. Borde
  3. Padding
  4. Contenido

Por ejemplo, si definimos este estilo:

.box {
    display: block;
    margin: 40px;
    padding: 20px;
    border: 5px solid blue;
    width: 300px;
    height: 300px;
}

Produciría este efecto (zona de margen mostrada en rojo):

margin, padding, border y content
margin, padding, border y content

En la imagen se puede ver como entre el contenido y el borde queda un espacio, el padding, luego aparece el borde y rodeando a todo el box aparece la zona de margin. Desde un punto de vista técnico, y a diferencia del borde, del padding y del propio contenido, el margen no forma parte del elemento en sí mismo. El margen es una zona externa al elemento.

Muchas veces se entiende, por pura intuición, que si damos un margen inferior de 20px a un elemento, y un margen superior de 40px al elemento situado justo debajo, entre ellos aparecerá un espacio de 60px, sin embargo, desde la versión 2.0 el box model viene con un regalo: el colapso de márgenes. Los márgenes verticales contiguos colapsan y entre esos elementos quedaría un margen de tan solo 40px. Sigue leyendo un poco más y explicaremos exactamente cuando y como ocurre esto.

¿Cuándo colapsan los márgenes?

Los márgenes horizontales no colapsan nunca, solo los verticales, es decir, los márgenes top y bottom, y colapsan siempre que dos márgenes verticales cualesquiera son contiguos y se «tocan», cuando no hay nada más entre ellos. Las situaciones de colapso se pueden clasificar en cuatro casos:

  1. Elementos adyacentes o contiguos
  2. Un contenedor y su primer elemento
  3. Un contenedor y su último elemento
  4. Bloques vacíos

El colapso de márgenes solo afecta al modelo de bloques, no afecta a otros modelos de display, por ejemplo al flex model (display: flex).

1. Elementos adyacentes

Si tenemos dos bloques contiguos o adyacentes, uno sobre otro, y el bloque de arriba tiene un margen inferior de 20px, y el bloque de abajo tiene un margen superior de 40px, el margen entre ambos será de 40px.

Un error bastante común es pensar que sería de 60px, que la distancia vertical entre ambos elementos resultaría de sumar ambos márgenes, pero los márgenes verticales se comportan como «quiero X distancia fuera del elemento como mínimo» y no como «mueve el elemento X distancia». Con el margen colapsado en 40px se respeta el margen mínimo de ambos elementos.

Supongamos este ejemplo:

<div class="div1"></div>
<div class="div2"></div>

Y le aplicamos es CSS:

.div1 {
    margin-bottom: 20px;
}
.div2 {
    margin-top: 40px;
}

Como ambos elementos son contiguos y sus márgenes verticales colapsan, el resultado será un margen entre ellos de 40px:

Colapso de márgenes verticales
Colapso de márgenes verticales

Colapso de márgenes positivos y negativos

Como se ha descrito, si los dos márgenes adyacentes son positivos, el margen resultante es el mayor de los dos. Por el contrario, si los dos márgenes son negativos, el margen resultante será el menor. Si un margen es positivo y el otro es negativo, el margen resultante es la diferencia entre el positivo y el negativo:

  • Dos márgenes positivos: margen resultante igual al margen mayor. Por ejemplo, si los márgenes son 50px y 25px, el margen resultante será 50px.
  • Dos márgenes negativos: el margen resultante es igual al margen menor. Por ejemplo, si los márgenes son -50px y -25px, el margen resultante será -50px.
  • Un margen positivo y otro negativo: el margen resultante es la diferencia entre ambos. Por ejemplo, si los márgenes son 50px y -25px, el margen resultante será de 25px (50 – 25).

2. Parent-first child

En elementos anidados dentro de otros, el primer elemento descendiente colapsa su margen superior con el margen superior del elemento padre. Las reglas son las mismas que antes. Por ejemplo, si los dos márgenes superiores son positivos, el margen superior resultante será el de mayor valor.

<div class="wrapper">
    <div class="div1"></div>
</div>
.wrapper {
    margin-top: 20px;
    height: 250px;
    background: grey;
}

.div1 {
    margin-top: 40px;
    width: 200px;
    height: 200px;
    background: blue;
}
Colapso de márgenes superiores parent-first child
Colapso de márgenes superiores parent-first child

Importantes excepciones: como se mencionó antes, el colapso ocurre cuando los márgenes verticales aparecen contiguos y se «tocan». El colapso entre un contenedor y su primer elemento NO ocurre si hay algo «sólido» que separe los dos márgenes; por ejemplo, si el elemento contenedor presenta contenido in-line antes del primer elemento hijo, por ejemplo algo de texto, o un borde, un padding o si se hace un clearing. Tampoco colapsan nunca los márgenes superiores del body y su primer elemento.

3. Parent-last child

De forma análoga a lo que ocurre en el caso anterior con los márgenes superiores, los márgenes inferiores del contenedor y de su último elemento también colapsan en uno solo. Y también como en el caso anterior, el colapso de márgenes no se produce si el borde o el padding del contenedor es mayor a cero, ni entre el body y su último elemento.

Colapso de márgenes inferiores parent-last child
Colapso de márgenes inferiores parent-last child

4. Bloques vacíos

Los márgenes verticales de un bloque vacío (sin height ni padding ni contenido) también colapsan entre sí. Por ejemplo, si tenemos un bloque vacío con un margen top de 40px y un margen bottom de 20px, el elemento ocupará una zona de 40px de altura al colapsar sus propios márgenes verticales:

<div class="dummy">Some dummy text</div>
<div class="empty"></div>
<div class="dummy">Some dummy text</div>
.dummy {
    margin: 0;
    height: 40px;
    padding: 10px;
    border: 2px solid;
    background: grey;
}
.empty {
    margin-top: 40px;
    margin-bottom: 20px;
}
Colapso de márgenes en bloques vacíos
Colapso de márgenes en bloques vacíos