Como desativar o colapso da margem?

202

Existe uma maneira de desativar completamente o colapso de margem? As únicas soluções que encontrei (com o nome "uncollapsing") envolvem o uso de uma borda de 1px ou preenchimento de 1px. Acho isso inaceitável: o pixel estranho complica os cálculos sem uma boa razão. Existe uma maneira mais razoável de desativar esse colapso de margem?

kjo
fonte
4
Use Flex ou a disposição da grade, onde não existe margem de colapso: stackoverflow.com/a/46496701/3597276
Michael Benjamin
Simplesmente dê um valor aos elementos, margin-bottommas deixe margin-topcomo 0. #
Dan Bray
Fiz um pacote para facilitar o cálculo: npmjs.com/package/collapsed-margin #
Owen M

Respostas:

254

Existem dois tipos principais de colapso de margem:

  • Recolhendo margens entre elementos adjacentes
  • Recolhendo margens entre elementos pai e filho

O uso de um preenchimento ou borda impedirá o colapso apenas no último caso. Além disso, qualquer valor overflowdiferente do padrão ( visible) aplicado ao pai evitará o colapso. Assim, ambos overflow: autoe overflow: hiddenterão o mesmo efeito. Talvez a única diferença ao usar hiddenseja a consequência não intencional de ocultar o conteúdo se o pai tiver uma altura fixa.

Outras propriedades que, uma vez aplicadas ao pai, podem ajudar a corrigir esse comportamento são:

  • float: left / right
  • position: absolute
  • display: inline-block / flex

Você pode testar todos eles aqui: http://jsfiddle.net/XB9wX/1/ .

Devo acrescentar que, como sempre, o Internet Explorer é a exceção. Mais especificamente, no IE 7, as margens não diminuem quando algum tipo de layout é especificado para o elemento pai, como width.

Fontes: artigo do Sitepoint Collapsing Margins

hqcasanova
fonte
1
Note-se que o preenchimento também pode afetar este se não for zero, o valor
Mladen Janjetovic
3
Observe que isso overflow: autopode fazer com que as barras de rolagem apareçam no elemento pai, em vez de permitir que o conteúdo excedente exceda o limite conforme overflow: visible.
Leo
'overflow: auto' parece não funcionar no Chrome v44.
precisa saber é o seguinte
3
Obrigado por display: inline-block, ele salvou-me :)
alexcasalboni
3
Qualquer valor flexdiferente de seu padrão também irá desativar colapso margem
Oly
60

Você também pode usar o bom e velho micro clearfix para isso.

#container:before, #container:after{
    content: ' ';
    display: table;
}

Consulte o violino atualizado: http://jsfiddle.net/XB9wX/97/

Blackgrid
fonte
Transformei minha resposta em um wiki da comunidade. Fique à vontade para estendê-lo com sua resposta. Obrigado.
Hqcasanova 24/10/2014
3
Eu não obtê-lo, quando eu ver esse exemplo as margens estão em colapso (somente 10px espaço vertical entre as divs em vez de 20px)
Andy
1
Isso ajuda apenas na remoção do colapso entre irmãos que todos têm esse clearfix aplicado. Eu peguei o exemplo para demonstrar isso: jsfiddle.net/dpyuyg07 --- e mesmo essa não é a história toda. Ele remove apenas o colapso das margens decorrentes dos filhos dos elementos em que você aplicou essa correção. Se você gostaria de acrescentar uma margem sobre o recipiente em si as margens ainda entraria em colapso, o que pode ser visto neste garfo: jsfiddle.net/oew7qsjx
NicBright
4
Posso colocar isso de maneira ainda mais precisa: o método clearfix impede apenas o colapso da margem entre pais e filhos. Não afeta o colapso entre irmãos adjacentes.
NicBright
Eu acho que agora eu entendo a tendência de Bootstrap para preencher o DOM com :beforee :afterelementos. Eu já adicionou esta regra ao meu estilo: div:before, div:after{content: ' '; display: table;}. Fantástico. De repente, as coisas começam a se comportar como esperado.
Stijn de Witt
59

Um truque interessante para desativar o colapso da margem que não tem impacto visual, tanto quanto eu sei, é definir o preenchimento do pai como 0.05px:

.parentClass {
    padding: 0.05px;
}

O preenchimento não é mais 0, portanto o colapso não ocorrerá mais, mas ao mesmo tempo o preenchimento é pequeno o suficiente para que visualmente seja arredondado para 0.

Se desejar algum outro preenchimento, aplique-o somente à "direção" na qual não é desejado o colapso da margem, por exemplo padding-top: 0.05px;.

Exemplo de trabalho:

.noCollapse {
  padding: 0.05px;
}

.parent {
  background-color: red;
  width: 150px;
}

.children {
  margin-top: 50px;

  background-color: lime;      
  width: 100px;
  height: 100px;
}
<h3>Border collapsing</h3>
<div class="parent">
  <div class="children">
  </div>
</div>

<h3>No border collapsing</h3>
<div class="parent noCollapse">
  <div class="children">
  </div>
</div>

Editar: alterou o valor de 0.1para 0.05. Como Chris Morgan mencionou em um comentário abaixo, e deste pequeno teste , parece que o Firefox leva 0.1pxem consideração o preenchimento. Embora, 0.05pxparece fazer o truque.

Nicu Surdu
fonte
2
Esta é a minha solução favorita. Você pode até incluir isso como um estilo padrão. Por que não? *{padding-top:0.1px}. Temos certeza de que funciona em todos os navegadores?
Nick Manning
Até agora, funcionou muito bem para mim, mas não pretendo testá-lo completamente na maioria dos navegadores.
Nicu Surdu
2
Solução muito boa, parece funcionar como esperado na maioria dos navegadores. Obrigado por compartilhar!
Wiredolphin
1
Esta é uma solução desonesto, pois não adicionar pixels extras em várias circunstâncias, devido à alta DPI displays e cálculos subpixel. (Firefox tem layout de subpixel feito para idades, eu acredito que outros navegadores têm relativamente pouco tempo seguiram o exemplo.)
Chris Morgan
0.05pxainda parece uma escolha específica, não um número de truque aleatório do navegador, eu preferiria 0.01px.
Volker E.
22

overflow:hidden evita o colapso das margens, mas não está livre de efeitos colaterais - ou seja, ... oculta o excesso.

Além de formar isso e o que você mencionou, basta aprender a viver com ele e aprender para este dia em que eles forem realmente úteis (vem a cada 3 a 5 anos).

Litek
fonte
Transformei minha resposta em um wiki da comunidade. Acho que abordei o efeito colateral que você mencionou nas duas últimas linhas do segundo parágrafo: Talvez a única diferença ao usar oculto seja a consequência não intencional de ocultar o conteúdo se o pai tiver uma altura fixa . Mas se você acha que precisa de mais esclarecimentos, sinta-se à vontade para contribuir. Obrigado.
Hqcasanova 24/10/2014
7
overflow: autoé bom usar para impedir o estouro oculto e ainda evitar o colapso das margens.
Gavin
@ Gavin, overflow:auto;fiz minha área de conteúdo ganhar uma barra de rolagem em algumas páginas.
Reed
13

Na verdade, existe um que funciona perfeitamente:

exibição: flex; direção flexível: coluna;

contanto que você possa suportar apenas o IE10 e superior

.container {
  display: flex;
  flex-direction: column;
    background: #ddd;
    width: 15em;
}

.square {
    margin: 15px;
    height: 3em;
    background: yellow;
}
<div class="container">
    <div class="square"></div>
    <div class="square"></div>
    <div class="square"></div>
</div>
<div class="container">
    <div class="square"></div>
    <div class="square"></div>
    <div class="square"></div>
</div>

Daniel Koster
fonte
Para que isso funcione como uma solução genérica, é preciso adicionar um extra <div>dentro do .container, caso contrário, .containerele controlará o modelo de caixa de seus filhos. Por exemplo, elementos embutidos se tornarão elementos de bloco de largura total; se tiverem margens, elas também serão reduzidas.
Zupa 19/09/19
9

Todo navegador baseado em webkit deve suportar as propriedades -webkit-margin-collapse . Também existem subpropriedades para configurá-lo apenas para a margem superior ou inferior. Você pode fornecer os valores recolhidos (padrão), descartar (define a margem como 0 se houver uma margem vizinha) e separar (impede o recolhimento da margem).

Eu testei que isso funciona nas versões de 2014 do Chrome e Safari. Infelizmente, acho que isso não seria suportado no IE porque não é baseado no webkit.

Leia a Referência CSS do Safari da Apple para obter uma explicação completa.

Se você verificar a página de extensões do webkit CSS da Mozilla , elas listam essas propriedades como proprietárias e recomendam não usá-las. Isso ocorre porque é provável que eles não entrem no CSS padrão tão cedo e apenas os navegadores baseados em webkit os darão suporte.

Dan Carter
fonte
Isso é bom porque nos ajuda a resolver uma inconsistência na maneira como o Safari e o Chrome lidam com as margens.
bjudson
8

Eu sei que esta é uma postagem muito antiga, mas só queria dizer que o uso do flexbox em um elemento pai desabilitaria o colapso da margem para seus elementos filhos.

Genzo
fonte
Não apenas para seus elementos filhos - também evita o colapso da margem entre o pai e o primeiro e o último filho.
Sven Marnach
2

Eu tive um problema semelhante com o colapso da margem por causa do pai ter position definido como relativo. Aqui está uma lista de comandos que você pode usar para desativar o recolhimento de margem.

AQUI ESTÁ PLAYGROUND PARA TESTAR

Apenas tente atribuir qualquer parent-fix*classe ao div.containerelemento ou qualquer classe children-fix*ao div.margin. Escolha aquele que melhor se adapte às suas necessidades.

Quando

  • o colapso da margem está desativado ,div.absolute com fundo vermelho vai ser posicionado no topo da página.
  • margem está entrando div.absolute em colapso será posicionado na mesma coordenada Y comodiv.margin

html, body { margin: 0; padding: 0; }

.container {
  width: 100%;
  position: relative;
}

.absolute {
  position: absolute;
  top: 0;
  left: 50px;
  right: 50px;
  height: 100px;
  border: 5px solid #F00;
  background-color: rgba(255, 0, 0, 0.5);
}

.margin {
  width: 100%;
  height: 20px;
  background-color: #444;
  margin-top: 50px;
  color: #FFF;
}

/* Here are some examples on how to disable margin 
   collapsing from within parent (.container) */
.parent-fix1 { padding-top: 1px; }
.parent-fix2 { border: 1px solid rgba(0,0,0, 0);}
.parent-fix3 { overflow: auto;}
.parent-fix4 { float: left;}
.parent-fix5 { display: inline-block; }
.parent-fix6 { position: absolute; }
.parent-fix7 { display: flex; }
.parent-fix8 { -webkit-margin-collapse: separate; }
.parent-fix9:before {  content: ' '; display: table; }

/* Here are some examples on how to disable margin 
   collapsing from within children (.margin) */
.children-fix1 { float: left; }
.children-fix2 { display: inline-block; }
<div class="container parent-fix1">
  <div class="margin children-fix">margin</div>
  <div class="absolute"></div>
</div>

Aqui está o jsFiddle com o exemplo que você pode editar

Buksy
fonte
1

No navegador mais recente (excluindo o IE11), uma solução simples para evitar o colapso da margem pai-filho é usar display: flow-root. No entanto, você ainda precisaria de outras técnicas para evitar o colapso do elemento adjacente.

DEMO (antes)

.parent {
  background-color: grey;
}

.child {
  height: 16px;
  margin-top: 16px;
  margin-bottom: 16px;
  background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>

DEMO (depois)

.parent {
  display: flow-root;
  background-color: grey;
}

.child {
  height: 16px;
  margin-top: 16px;
  margin-bottom: 16px;
  background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>

Chuanqi Sun
fonte
0

Para sua informação, você pode usar a grade, mas com efeitos colaterais :)

.parent {
  display: grid
}
Whisher
fonte