Por que esse estilo de margem de CSS não funciona?

321

Eu tento adicionar valores de margem em uma div dentro de outra div. Tudo funciona bem, exceto o valor máximo, parece ser ignorado. Mas por que?

O que eu esperava:
O que eu esperava com margem: 50px 50px 50px 50px;

O que eu ganho:
O que recebo com margem: 50px 50px 50px 50px;

Código:

#outer {
    	width: 500px; 
    	height: 200px; 
    	background: #FFCCCC;
    	margin: 50px auto 0 auto;
    	display: block;
}
#inner {
    	background: #FFCC33;
    	margin: 50px 50px 50px 50px;
    	padding: 10px;
    	display: block;
}
<div id="outer">
  <div id="inner">
  	Hello world!
  </div>
</div>

O W3Schools não tem explicação para o porquê da margem se comportar dessa maneira.

jamietelin
fonte
4
você tentou flutuar o interior?
Galo
6
hum .. Com float:left;isso funciona ... mas por que isso é necessário. Eu não quero que flutue. E por que a margem para esquerda / direita funciona?
jamietelina
44
Bem-vindo ao mundo divertido do algoritmo de colapso da margem CSS!
GordonM
10
W3Schools vs. W3CDocs ... Acho que temos um vencedor. : D
habilidade final
15
jsFiddle disso, para salvar o próximo cara 25 segundos jsfiddle.net/kLeu9
CodyBugstein

Respostas:

453

Você está vendo a margem superior do #innerelemento colapsar na borda superior do elemento#outer elemento, deixando apenas a #outermargem intacta (embora não seja mostrada em suas imagens). As bordas superiores de ambas as caixas estão alinhadas uma com a outra porque suas margens são iguais.

Aqui estão os pontos relevantes da especificação do W3C:

8.3.1 Recolhendo margens

No CSS, as margens adjacentes de duas ou mais caixas (que podem ou não ser irmãos) podem ser combinadas para formar uma única margem. Diz-se que as margens que se combinam dessa maneira entram em colapso e a margem combinada resultante é chamada de margem recolhida .

Margens verticais adjacentes colapsam [...]

Duas margens são adjacentes se e somente se:

  • ambos pertencem a caixas no nível de bloco em fluxo que participam do mesmo contexto de formatação de bloco
  • sem caixas de linha, sem folga, sem preenchimento e sem borda separá-los
  • ambos pertencem a bordas de caixas adjacentes verticalmente, ou seja, formam um dos seguintes pares:
    • margem superior de uma caixa e margem superior de seu primeiro filho em fluxo

Você pode executar um dos seguintes procedimentos para impedir que a margem entre em colapso:

O motivo pelas quais as opções acima impedem o colapso da margem é:

  • As margens entre uma caixa flutuante e qualquer outra caixa não caem (nem mesmo entre uma bóia e seus filhos em fluxo).
  • As margens de elementos que estabelecem novos contextos de formatação de bloco (como flutuadores e elementos com 'estouro' diferente de 'visível') não entram em colapso com seus filhos em fluxo.
  • As margens das caixas de bloco em linha não caem (nem mesmo com seus filhos em fluxo).

As margens esquerda e direita se comportam conforme o esperado, porque:

As margens horizontais nunca caem.

BoltClock
fonte
12
Aparentemente, você não é o único a pensar que é estúpido ...
BoltClock
2
Essa resposta é demais! Apenas algo a acrescentar. Sua citação do w3c diz isso, mas eu só percebi agora. Portanto, para deixar claro para os outros, você também pode dar uma #fronteira.
Driechel
O link no flutuante parece estar quebrado.
EP
@episanty: é o que acontece quando você vincula um comentário. Desvinculado.
BoltClock
Eu sei - só queria que você soubesse. Como você está habilitado para ♦, achei que você poderia ressuscitar o comentário - ou alterar sua postagem de acordo. Obrigado pela boa resposta, a propósito.
EP
92

Tente usar display: inline-block;na div interna.

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
}
#inner {
    background:#FFCC33;
    margin:50px 50px 50px 50px;
    padding:10px;
    display:inline-block;
}
enderskill
fonte
6
Boa resposta. Seria melhor se explicasse por que essa alteração corrige o problema.
31412 JohnFx
1
Ok, isso é esquisito! Por que isso funciona? Qual é a explicação lógica para o porquê de não funcionar como seria de esperar? Margem esquerda / direita funciona sem display:inline-block;. Também recuado ao usar display:inline-block;é que você perde a largura de 100% na div.
jamietelin
3
alterná-lo para bloco embutido força o navegador a reavaliar o tamanho da div após sua colocação e outras regras serem aplicadas.
Galo
Tentei para o meu problema, fez um efeito de escada.
9136 Jonny
1
display:inline-blocktrabalhou para mim. Muito obrigado.
starkeen
24

O que o @BoltClock mencionado é bastante sólido. E aqui eu só quero adicionar várias outras soluções para esse problema. verifique esta margem w3c_collapsing . As partes verdes são o pensamento potencial de como esse problema pode ser resolvido.

Solução 1

As margens entre uma caixa flutuante e qualquer outra caixa não caem (nem mesmo entre uma bóia e seus filhos em fluxo).

isso significa que posso adicionar float:lefta #outerou #inner demo1 .

Observe também que floatisso invalidaria a automargem de entrada.

Solução 2

As margens de elementos que estabelecem novos contextos de formatação de bloco (como flutuadores e elementos com 'estouro' diferente de 'visível') não entram em colapso com seus filhos em fluxo.

outro que não seja visible , put Vamos overflow: hiddenem #outer. E esse caminho parece bem simples e decente. Eu gosto disso.

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    overflow: hidden;
}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;
}

Solução 3

As margens das caixas absolutamente posicionadas não caem (nem mesmo com seus filhos em fluxo).

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    position: absolute; 
}
#inner{
    background: #FFCC33;
    height: 50px;
    margin: 50px;
}

ou

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    position: relative; 
}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;
    position: absolute;
}

esses dois métodos interromperão o fluxo normal de div

Solução 4

As margens das caixas de bloco em linha não caem (nem mesmo com seus filhos em fluxo).

é o mesmo que @enderskill

Solução 5

A margem inferior de um elemento em nível de bloco em fluxo sempre cai com a margem superior de seu próximo irmão em nível de bloco em fluxo, a menos que esse irmão tenha folga.

Isso não tem muito trabalho a ver com a questão, pois é a margem em colapso entre os irmãos. geralmente significa se uma caixa superior possui margin-bottom: 30pxe uma caixa irmão possui margin-top: 10px. A margem total entre eles é em 30pxvez de40px .

Solução 6

A margem superior de um elemento de bloco em fluxo entra em colapso com a primeira margem superior da criança em nível de bloco em fluxo, se o elemento não tiver borda superior, preenchimento superior e a criança não tiver folga.

Isso é muito interessante e posso apenas adicionar uma linha de borda superior

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    border-top: 1px solid red;

}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;

}

E também <div>é o nível de bloco no padrão, assim você não precisa declarar isso de propósito. Desculpe por não poder postar mais de 2 links e imagens devido à minha reputação de iniciante. Pelo menos você sabe de onde vem o problema da próxima vez que vir algo semelhante.

Qiang
fonte
14

Não sei por que o que você tem não funciona, mas você pode adicionar

overflow: auto;

para a div externa

Brandon
fonte
Cargas de soluções diferentes para esse problema. Obrigado! Esta resposta combinada com a resposta do @ BoltClock fornece boas informações sobre por que essa solução funciona.
jamietelin
12

Se você adicionar algum preenchimento #outer, ele funcionará.

Demo

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
    padding-top:1px;
}
estante de livros
fonte
11

Não sei exatamente por que, mas alterar o CSS interno para

display:inline-block;

parece funcionar;

harriyott
fonte
3

Não responde o "porquê" (deve ser algo com margem em colapso), mas parece que a maneira mais fácil / lógica de fazer o que você está tentando fazer é apenas adicionar padding-topà div externa :

http://jsfiddle.net/hpU5d/1/

Nota secundária - não deve ser necessário definir uma div, a display:block;menos que haja algo mais no seu código que diga para não ser bloqueado.

Dave
fonte
3

tente isto:

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;
}
#inner {
    background:#FFCC33;
    margin:50px 50px 50px 50px;
    padding:10px;
    display:block;
}​

http://jsfiddle.net/7AXTf/

Boa sorte

Mustafa M Jalal
fonte
2

Eu acho que definir a propriedade position da div #inner para relativa também pode ajudar a alcançar o efeito. De qualquer forma, tentei o código original colado na pergunta no IE9 e no Google Chrome mais recente e eles já dão o efeito desejável sem nenhuma modificação.

viditkothari
fonte
2

Use padding-top:50pxpara div externo. Algo assim:

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;}

Nota: o preenchimento aumentará o tamanho da sua div. Nesse caso, se o tamanho da sua div for importante, quero dizer se ela deve ter uma altura específica. diminua a altura em 50px .:

#outer {
    width:500px; 
    height:150px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;}
Ata Iravani
fonte
1

Você já tentou! Importante antes de tudo, forçará tudo:

margin:50px 50px 50px 50px !important;
atgr24869
fonte
-1

Apenas para uma solução rápida, tente agrupar os elementos filhos em um divelemento como este -

<div id="outer">
   <div class="divadjust" style="padding-top: 1px">
      <div id="inner">
         Hello world!
      </div>
   </div>
</div>

A margem de innerdiv não entrará em colapso devido ao preenchimento 1pxentre outere innerdiv. Então, logicamente, você terá 1pxespaço extra junto com a margem existente de innerdiv.

Mithilesh Tipkari
fonte