Boas práticas para evitar problemas com margin collapsing em CSS
Tags: margincollapsing, margin, css, html
Published: 2023-03-21 03:24:46

## O margin collapsing pode causar problemas em seu layout. Por sorte, o CSS já está preparado para resolver o seu design.
 
Veja o conteúdo abaixo:
 
```html
<p>Primeiro texto</p>
<p>Segundo texto</p>
```
 
```css
p {
  margin-top: 10px;
  margin-bottom: 10px;
}
```
 
E agora responda: quantos pixels de espaçamento existem entre o primeiro e o segundo parágrafo:
 
1. 0px
2. 10px
3. 20px
4. Girafa
 
Se você respondeu 0px, largue as drogas.
 
Se respondeu 10px, já sabe do que vou falar. O que está fazendo aqui? Brincadeira, fica, vai ter bolo.
 
Se respondeu 20px, esse post é para você.
 
Agora, se respondeu girafa... tá tudo bem?
 
Assim como falei nesse [post sobre box model](https://demenezes.dev/posts/css-box-model-elementos-tamanhos-inesperados/), HTML é um monte de caixinhaa dentro de caixinha. Os componentes que formam elas são:
 
- Conteúdo
- Padding
- Border
- Margin
 
Se quiser entender melhor, revise alguns conceitos no post antes de prosseguir.
 
---
 
Agora vou falar sobre:
 
- O que é o margin collapsing
- As 3 situações onde ele acontece
- Margin collapsing com mais de duas margens
- Cálculo
- Como corrigir
 
Agora que o box model está mais claro para você, eu começo com a definição da palavra.
 
## O que é margin collapsing?
 
Antes de tudo, o que é margin?
 
Margin é uma das propriedades CSS que compõem o box model. O seu valor cria um espaçamento para os elementos próximos nas quatro direções: cima, direita, baixo, esquerda (parece golpe do Street Fighter).
 
Seu objetivo é criar um espaço entre ele e um elemento irmão. Margin não serve (ou não deveria servir) para separar um elemento filho de um pai.
 
**Em alguns momentos, você vai encontrar algumas margens que se encostam, sem nada entre elas. Elas podem ser do mesmo elemento ou de elementos diferentes. Nesse momento, acontece o margin collapsing, que é quando as duas margens se sobrepõem e ocupam o mesmo espaço na tela.**
 
É importante deixar claro que isso só acontece com `margin-top` e `margin-bottom`, e nunca com `margin-left` e `margin-right`.
 
Mas o **margin collapsing** não acontece sempre.
 
## Quando o margin collapsing acontece
 
O margin collapsing acontece em 3 situações.
 
### 1. Elementos irmãos próximos
 
É o caso mais clássico.
 
Quando dois elementos irmãos são posicionados verticalmente, o `margin-bottom` do primeiro se junta com o `margin-top` do segundo.
 
![margin-bottom de um elemento colidindo com o margin-top do próximo elemento](https://www.datocms-assets.com/64896/1679266545-um-margin-bottom.png)
 
![margin-topde um elemento colidindo com o margin-bottom do elemento anterior](https://www.datocms-assets.com/64896/1679266530-um-margin-top.png)
 
### 2. Elemento pai com primeiro e último filho
 
Briga de família aqui.
 
![margin-top e margin-bottom do elemento pai que envolve dois parágrafos](https://www.datocms-assets.com/64896/1679266644-pai-filho-2.png)
 
O margin collapsing acontece entre o `margin-top` do elemento pai e o `margin-top` do primeiro filho:
 
![margin-top do elemento pai e primeiro filho colidindo](https://www.datocms-assets.com/64896/1679266598-pai-filho-1.png)
 
E entre o `margin-bottom` do elemento pai com o `margin-bottom` do último filho:
 
![margin-bottom do elemento pai e último filho colidindo](https://www.datocms-assets.com/64896/1679266620-pai-filho-3.png)
 
Perceba que nesse caso, o collapsing acontece entre duas margens no mesmo sentido: para cima ou para baixo.
 
Caso a margem que se destaque seja do elemento filho (por exemplo, o segundo parágrafo), ela é "virtualmente" transferida ao pai (`div-1`). Assim, ele cria um espaço para seus irmãos (outras divs irmãs da `div-1`). Mas se olhar pelo devtools, ela permanece no filho.
 
### 3. Elemento vazio
 
Entende-se um elemento vazio como sem valor, logo ele praticamente some da tela.
 
Se um elemento HTML estiver vazio, o `margin-top` e `margin-bottom` dele se colapsam.
 
![margin collapsing de um elemento vazio](https://www.datocms-assets.com/64896/1679266665-vazio-1.png)
 
![elemento vazio sendo ignorado e sobreposto pelo próximo elemento](https://www.datocms-assets.com/64896/1679266668-vazio-2.png)
 
Perceba que é como se o terceiro parágrafo ignorasse a existência do segundo parágrafo, o vazio.
 
---
 
Entender as 3 situações onde o margin collapsing acontece, não é muito complicado. Porém agora você verá outros detalhes sobre esse fenômeno.
 
## Margin collapsing com mais de duas margens
 
Preciso dizer que eu menti.
 
Você lembra que eu disse "*o margin collapsing é quando duas margens se sobrepõem*"? Não era bem verdade, pois **mais de duas margens podem estar envolvidas em um collapsing**.
 
Para isso, é necessário combinar 2 dos 3 casos que expliquei (ou todos eles):
 
```html
<div class="div-1">
  <p>Texto</p>
</div>

<div class="div-2">
  <p>Texto</p>
</div>
```
 
```css
.div-1 {
  margin-bottom: 5px;
}

.div-1 p {
  margin-bottom: 15px;
}

.div-2 {
  margin-top: 20px;
}

.div-2 p {
  margin-top: 10px;
}
```
 
Todas as margens que declarei acima, se sobrepõem, basta testar o código para confirmar.
 
E após toda essa salada de margins, é possível ver que o espaço final foi de 20px, exatamente o `margin-top` da `div-2`.
 
Mas como isso foi definido?
 
## Como calcular o valor final de um margin collapsing
 
Quando duas ou mais margens se sobrepõem, o navegador calcula a margem final.
 
Apesar de saber que ele fará esse trabalho para você, é importante entender como esse cálculo é feito. Assim, você começa a se aprofundar nos conceitos de como o navegador e a web funcionam.
 
### Margens positivas
 
Foi o caso do exemplo anterior.
 
Se duas ou mais margens positivas estiverem em um collapsing, o resultado final será a maior margem:

| Margins envolvidas no collapsing | Margin final |
| -------------------------------- | ------------ |
| 5px                              | 35px         |
| 35px                             |              |
| 20px                             |              |
 
### Margem positiva com outra zerada
 
Nesse caso, segue a mesma regra anterior: permanece a maior margem, ou a única margem positiva:

| Margins envolvidas no collapsing | Margin final |
| -------------------------------- | ------------ |
| 5px                              | 18px         |
| 18px                             |              |
| 0px                              |              |
 
### Margens negativas

| Margins envolvidas no collapsing | Margin final |
| -------------------------------- | ------------ |
| -5px                             | -20px        |
| -20px                            |              |
| -15px                            |              |
 
Se apenas margens negativas estiverem envolvidas, o resultado final será a menor margem:
 
### Margin negativa com positiva
 
Quando houver margens de sinais diferentes, basta somar os extremos: a maior com a menor.
 
| Margins envolvidas no collapsing | Cálculo        | Margin final |
| -------------------------------- | -------------- | ------------ |
| 35px                             | 35px + (-15px) | 20px         |
| 5px                              |                |              |
| -10px                            |                |              |
| -15px                            |                |              |

Se houver apenas duas margens, some elas.
 
Se houver mais de duas, ignore as margens com valores intermediários no cálculo.
 
---
 
E agora finalmente, como se livrar desse incômodo.
 
## Como corrigir o margin collapsing?
 
Você se lembra do capítulo *Quando o margin collapsing acontece*? Agora você verá como corrigi-lo, ou *Quando o margin collapsing não acontece*.
 
Para isso, basta apenas quebrar uma das exigências do margin collapsing. Existem muitas formas de fazer isso. Veja algumas:
 
### Use float
 
Obs: não use mais float :) flexbox e grid estão aí para isso.
 
Mas se usar, saiba que não haverá margin collapsing em elementos flutuantes.
 
Resolve os seguintes casos:
 
- Elementos irmãos próximos
- Elemento pai com primeiro e último filho
- Elemento vazio
 
### Use position
 
Um elemento posicionado não irá causar margin collapsing.
 
Isso vale tanto para `position: absolute`, quanto para `position: fixed`.
 
Resolve os seguintes casos:
 
- Elementos irmãos próximos
- Elemento pai com primeiro e último filho
- Elemento vazio
 
### Use padding
 
No começo do post, eu disse que o collapsing acontece quando duas margens se encostam. Logo, se as margens não se encostam, não acontece o collapsing.
 
A forma mais simples de fazer isso é adicionar um padding em um dos elementos.
 
Resolve os seguintes casos:
 
- Elemento pai com primeiro e último filho
- Elemento vazio
 
### Use border
 
A borda é outro componente do box model que, ao ser inserida, impede o margin collapsing.
 
Resolve os seguintes casos:
 
- Elemento pai com primeiro e último filho
- Elemento vazio
 
### Use propriedades de altura
 
Essas propriedades de altura evitam o margin collapsing:
 
- `height`
- `min-height`
- `max-height`
- `line-height`
 
A regra diz que as margens precisam se tocar para acontecer o collapsing. Logo, definir uma altura é o suficiente para separá-las.
 
Resolve os seguintes casos:
 
- Elemento pai com primeiro e último filho
- Elemento vazio
 
### Use overflow
 
Se o elemento pai tiver uma barra de rolagem em função da propriedade `overflow`, não haverá margin collapsing. Isso acontece tanto com `overflow: scroll`, quanto com `overflow: auto`.
 
É importante que esse elemento também não seja vazio.
 
Resolve os seguintes casos:
 
- Elemento pai com primeiro e último filho
 
### Insira um conteúdo entre as bordas
 
O margin collapsing não acontece caso haja qualquer conteúdo entre as duas (ou mais) margens. 
 
Esse conteúdo pode ser até a tag `<br />`. Mas venhamos e convenhamos, você não vai fazer isso né?
 
Resolve os seguintes casos:
 
- Elemento pai com primeiro e último filho
- Elemento vazio
 
### Use flexbox ou grid
 
A maravilha do CSS moderno.
 
Se você colocar `display: flex / grid` em um elemento, não irá acontecer o margin collapsing entre seus filhos.
 
Resolve os seguintes casos:
 
- Elementos irmãos próximos
 
Some a isso, o fato de você poder separar elementos dentro de flexbox e grid com a&nbsp;[propriedade gap do CSS](https://developer.mozilla.org/pt-BR/docs/Web/CSS/gap). A maioria dos&nbsp;[navegadores modernos já suporta essa propriedade, segundo o Can I Use](https://caniuse.com/?search=gap). Assim, nem é preciso usar&nbsp;`margin`.
 
## Callback
 
Margin collapsing é quando o `margin-top`/`margin-bottom` de um elemento se junta com o de outro ou do mesmo elemento.
 
Acontece entre:
 
- Elementos irmãos próximos
- Elemento pai com primeiro e último filho
- E elementos vazios
 
Pode acontecer com mais de duas margens ao mesmo tempo.
 
Dependendo do valor das margens envolvidas, o valor final pode variar bastante em função do cálculo.
 
Existem também diversas formas de corrigir o margin collapsing, e cada uma se aplica a uma situação diferente.
 
O que achou? Diferente de mim, você encontra muito margin collapsing no seu dia a dia?
 
Comente aqui aqui embaixo!
 
Muito obrigado pela sua leitura 🙂
 
---
 
Continue estudando:
 
- [https://developer.mozilla.org/pt-BR/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing](https://developer.mozilla.org/pt-BR/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing)
- [https://blog.cisne.dev/desmistificando-o-margin-collapsing-do-css/](https://blog.cisne.dev/desmistificando-o-margin-collapsing-do-css/)
- [https://www.joshwcomeau.com/css/rules-of-margin-collapse/](https://www.joshwcomeau.com/css/rules-of-margin-collapse/)
- [https://www.freecodecamp.org/news/what-is-margin-collapse-and-how-to-avoid-it/](https://www.freecodecamp.org/news/what-is-margin-collapse-and-how-to-avoid-it/)
- [https://css-tricks.com/what-you-should-know-about-collapsing-margins/](https://css-tricks.com/what-you-should-know-about-collapsing-margins/)