Entendiendo el Colapso de Márgenes (Margin Collapsing) 😓
Tags: css, spanish, latam
Published: 2021-06-15 21:51:23

¡Hola gente bonita!👋

Hay una situación en la que el margen entre un elemento y el de un elemento vecino se fusionarán (o colapsarán) en un espacio unificado. Los márgenes colapsables pueden ser una molestia si no se entiende bien cuándo se producen. El primer paso para tratar con ellos o evitarlos es entender exactamente con qué caso de márgenes colapsables estamos tratando.

Antes de entender como funciona el colapso de márgenes quiero asegurarme de que todos entendemos cual es el margen en nuestro modelo de caja (box-model).

##📦 Modelo de caja - Margin

El margen es un espacio vacío que podemos usar para crear espacio entre una caja y otra en nuestro diseño.

![box model](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5h8byogi4mzsiuxxe7jw.png)

Si quieres conocer a detalle sobre el modelo de caja, escribi un [articulo completo](https://dev.to/lupitacode/que-es-el-box-model-4mnj) sobre este tema. 

##📄 user-agent stylesheet

Los navegadores vienen con una sorprendente cantidad de CSS por defecto, que llamamos user-agent stylesheets (hojas de estilo del agente de usuario). Estos estilos son la razón por la que, sin ningún tipo de CSS por nuestra parte, un `<h1>` es más grande que un `<h2>`, y por la que el `<body>` tiene un margen que muchas veces hay que eliminar.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ph767z937bzzuloshb6.png)

Estos estilos son importantes, pero también conducen a uno de los mayores problemas que los desarrolladores se encuentra con los márgenes. Los márgenes no son por defecto 0 en todos los elementos HTML, y esto puede causar todo tipo de problemas extraños que exploraremos en breve.

Las listas, los párrafos y los encabezados tienen márgenes (entre otros elementos). Aunque a veces sólo son un pequeño inconveniente, el margen por defecto de los párrafos y los encabezados parece ser el que causa más problemas desde el principio.

Por defecto, los márgenes izquierdo y derecho de un elemento de texto se establecen en 0, pero la mayoria de los elementos vienen con un margen superior (margin-top) y un margen inferior (margin-bottom).

Esto significa que existe un espacio extra entre los elementos de nuestra página aunque no hayamos establecido explícitamente un margen.

##↕️ ¿Qué es un margen colapsado?

Ahora bien, cuando dos elementos de bloque HTML tienen márgenes verticales que se tocan entre sí, estos dos márgenes colapsan en uno o se fusionan entre sí, y aquí dominará el más grande.

La documentación de la W3C define el colapso de márgenes de la siguiente manera:

> "En CSS, los márgenes adyacentes de dos o más bloques (que podrían o no ser hermanos) pueden combinarse para formar un único margen. Cuando los márgenes se combinan de esta manera decimos que colapsan, y el margen combinado resultante se denomina margen colapsado." 

Por lo tanto, los "márgenes adyacentes" son márgenes que están uno al lado del otro, y pueden combinarse para formar un único margen. Pero, ¿esto significa que todos los márgenes adyacentes pueden colapsar? ¡La respuesta es no! sólo es para márgenes verticales (superior e inferior).

El colapso de margen ocurre en cuatro casos básicos:

☝️ Hermanos adyacentes.
✌️ Un contenedor padre y su primer elemento hijo.
👌 Un contenedor padre y su último elemento hijo.
✊ Bloques vacíos.

##⊟ Caso 1 (Hermanos adyacentes)
Este ejemplo visual es la mejor manera de entenderlo:

```
<div class="box-1">Esta caja tiene<span>margin-bottom:40px;</span>
</div>

<div class="box-2">Esta caja tiene <span>margin-top:40px;</span></div>
```

```
.box-1 {
    margin-bottom: 40px; ⬅
    padding: 20px;
    border: solid 5px red;
}
.box-2 {
    margin-top: 40px; ⬅
    padding: 20px;
    border: solid 5px blue;
}

span {
    font-weight: bold;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o426ek9d5ch5arnvl6bc.png)

Cuando los desarrolladores hace algo así, espera que el margen de la primera caja y la segunda sea de 80px (40px + 40px), pero en realidad es de 40px. Los dos márgenes se tocan entre sí, por lo que se combinan o se colapsan el uno con el otro.

El margen inferior del elemento se colapsa con el margen superior del siguiente elemento.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/spn2hwssarl051h53x2c.png)

Ahora para empujar aún más, vamos a dar a nuestra primera caja un margen inferior (margin-bottom) de 100px:

```
.box-1 {
    margin-bottom: 100px;
}
.box-2 {
    margin-top: 40px;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/whn9aum2xgm3vihtvize.png)

Como podemos observan en la imagen el margen más grande siempre gana, es decir, como la primera caja tiene un margen de 100px y la otra caja 40px el que termina ganando es el que tenga un valor superior, podemos decir que hay 100px de margen entre la primera y la segunda caja. 

Recuerda que en estos ejemplos los márgenes no se suman. 

El colapso de márgenes solo afecta a los elementos de bloque `display: block`, no afecta a otros valores de la propiedad display, por ejemplo a `display: flex`.

###➕➖ 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 margen más pequeño (el más negativo). 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.

* Cuando todos los márgenes son negativos, el tamaño del margen colapsado es el negativo más grande de los dos en lugar del que está más cerca de ser positivo. Por ejemplo, si los márgenes son -50px y -25px, el margen resultante será -50px. Esto se aplica tanto a los elementos adyacentes como a los elementos anidados.

* 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). El tamaño del margen colapsado es la suma del margen positivo más grande y el margen negativo más pequeño (el más negativo).

##👨‍👦 Caso 2 - Un contenedor padre y su primer elemento.

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.

### Ejemplo 1

Estamos colocando nuestro primer elemento `<div>` dentro de su contenedor padre.

El margen hijo está siendo "absorbido" por el margen padre. Los dos se combinan y están sujetos a las mismas reglas de colapso de márgenes que hemos visto hasta ahora (por ejemplo, el más grande gana).

```
 <div class="parent">
    <div class="child"></div>
 </div>
```
```
body {
    margin: 0;
    font-family: arial;
}

.parent {
    margin-top: 50px;
    height: 250px;
    background: grey;
}

.child {
    margin-top: 40px;
    width: 200px;
    height: 200px;
    background: blue;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ytmjc7hsi4ud9glsj5nk.png)

Como puedes observar en la imagen los márgenes seguirán colapsados
¿Cómo puede ser esto? Pues resulta que muchos de nosotros tenemos una idea equivocada sobre el funcionamiento de los márgenes.

El margen sirve para aumentar la distancia entre hermanos. No está pensado para aumentar la distancia entre un hijo y el cuadro delimitador de su padre; para eso está el padding.

Si añadimos un borde alrededor del elemento padre, los márgenes ya no se colapsan esto sucederia porque el margen del padre ya no estaria en contacto directo con el margen del hijo.

**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 que separe los dos márgenes; por ejemplo, si el elemento contenedor presenta contenido inline antes del primer elemento hijo, por ejemplo algo de texto, un borde o un padding.

Puedes pensar en el padding/border como una especie de muro; si se sitúa entre dos márgenes, éstos no pueden colapsar, porque hay un muro en el camino, incluso 1px de padding interferirá con el colapso de los márgenes.

### Ejemplo 2
En este ejemplo vamos a tener un `header` y dentro de el un encabezado `<h1>`.

```
<header class="header">
   <h1 class="title">Lupita code</h1>
</header>
```
```
body {
    margin: 0;
    font-family: arial;
    background-color: #ccc;
}

.header {
    height: 50px;
    background-color: steelblue;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/62lx772642wqs7aujqhh.png)

Como podemos observar en la imagen hay un espacio entre la parte superior del viewport y el `header`, ese espacio extra no corresponde al `body` ya que si te fijas en el código CSS, el `body` tiene un margen con valor de 0. ¿Adivinas de dónde viene? 

Ese margen tampoco es del `header` lo que nos lleva a concluir que ese margen le corresponde al encabezado `<h1>`, y si revisas la herramienta de desarrollo te puedes dar cuenta que el encabezado ya viene con un margen vertical de la hoja de estilo del navegador.

¿Recuerdas cuando mencioné sobre las hojas de estilo del navegador?

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ph767z937bzzuloshb6.png)

La solución es colocar un `margin: 0` al `<h1>` y así ya no se tiene esa separación. El resultado es el siguiente:

```
.title {
    margin: 0;
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0vvlopfd2gvbayj84i35.png)

Ahora quiero agregar nuevamente un `margin-top` de 10px al `<h1>`

```
.title {
    margin: 0;
    margin-top: 20px;
}
``` 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k0if3i1a62csqcq41mm1.png)

Como puedes observar el `header` se movió, y se supone que solo le indicamos que se moviera el `<h1>`. Para que esto no ocurra, tenemos varias soluciones:

1. Añadir la declaración `overflow: hidden` al `header`.
2. Añadir un `padding-top` al `header`.
3. Añadir un `border-top` al header.

Si añadimos padding, border o espacio a los elementos de los ejemplos anteriores, no se aplicará el colapso. En otras palabras, una forma de deshacerse del comportamiento del colapso de márgenes consiste en añadir algún tipo de separación (borde, padding o espacio libre) entre los márgenes.

## Caso 3 - Un contenedor padre y su último elemento.

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.

```
<div class="parent">
   <div class="child">Here is a paragraph</div>
</div>
<div class="div">Outside the parent</div>
``` 
```
body {
    margin: 0;
    font-family: arial;
}

.parent {
    margin-bottom: 30px;
    background: #49b293;
    height: auto;
}
.child {
    margin-bottom: 50px;
    background: blue;
    height: 100px;
    width: 200px;
}

.div {
    background-color: red;
}

```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h2y30aa5kcmbfntbwljc.png)

## Caso 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="box">Lorem, ipsum.</div>
<div class="empty"></div>
<div class="box">Lorem, ipsum.</div>
```
```
body {
    margin: 0;
    font-family: arial;
}

.box {
    margin: 0;
    height: 40px;
    padding: 10px;
    border: 2px solid;
    background: khaki;
}
.empty {
    margin-top: 40px;
    margin-bottom: 20px;
}

```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9q0pjqki9yk40ouimycc.png)

## Excepciones

Como en todo, hay algunas excepciones a tener en cuenta cuando los márgenes no se colapsan.

1. Flexbox, Grid y otros elementos que no son de nivel de bloque.

El colapso de márgenes no se aplican a los flex items, grid items, a los elementos de posición absoluta ni a otros elementos que no sean de nivel de bloque.

## 📋 Conclusión

☑️ Un margen colapsado es lo que ocurre cuando se combinan dos elementos a nivel de bloque con márgenes verticales coincidentes. Cuando esto sucede, el mayor de los dos márgenes se asume como el único margen colapsado.
☑️ No se aplica a márgenes horizontales.
☑️ Sólo ocurre con los elementos a nivel de bloque es decir, `display: block` - esto no incluye los elementos inline-block.
☑️ Hay 4 casos en los que se genera un colapso de márgenes. 
☑️ La especificación CSS es enorme. No intentes saberlo todo. Aprende los conceptos de alto nivel y las reglas comunes, busca cosas cuando las necesites y tómatelo con calma.

##🔎Recursos:
* [Entendiendo el colapso de margen | MDN](https://developer.mozilla.org/es/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing)

* [Fundamentos de CSS: Comprensión del colapso de márgenes] (https://webdesign.tutsplus.com/es/tutorials/css-basics-understanding-collapsing-margins--cms-34272)

* [The Rules of Margin Collapse | Josh Comeau](https://www.joshwcomeau.com/css/rules-of-margin-collapse/)

* [What's the Deal with Collapsible Margins?](https://bitsofco.de/collapsible-margins/)

* [Margin Collapse in CSS: What, Why, and How](https://medium.com/@joseph0crick/margin-collapse-in-css-what-why-and-how-328c10e37ca0)

* [El caso del colapso de márgenes en CSS](https://cybmeta.com/colapso-de-margenes-en-css)

* [Negative margins in CSS](https://www.quirksmode.org/blog/archives/2020/02/negative_margin.html)

Gracias por leer🦸🏻‍♀️
Mis redes sociales donde comparto notas de código:

[▶️Youtube](https://www.youtube.com/lupitacode)
[📷Instagram](https://instagram.com/lupitacode)
[🐦Twitter](https://twitter.com/lupitacode)
[🔵Facebook](https://facebook.com/lupitacode)
[🔲Codepen](https://codepen.io/lupitacode/)
[✍️Medium](https://lupitacode.medium.com/)
[🎵Tik Tok](https://www.tiktok.com/@lupitacode)