Margem no elemento filho move o elemento pai

415

Eu tenho um div( pai ) que contém outro div( filho ). Pai é o primeiro elemento bodysem um estilo CSS específico. Quando eu definir

.child
{
    margin-top: 10px;
}

O resultado final é que a parte superior do meu filho ainda está alinhada com a mãe. Em vez de o filho ser deslocado para 10 px para baixo, meu pai move 10 px para baixo.

Meu DOCTYPEestá definido como XHTML Transitional.

O que estou perdendo aqui?

editar 1
Meu pai precisa ter dimensões estritamente definidas porque possui um plano de fundo que deve ser exibido abaixo, de cima para baixo (pixel perfeito). Portanto, definir margens verticais não é possível .

editar 2
Esse comportamento é o mesmo no FF, IE e CR.

Robert Koritnik
fonte
188
esse comportamento não faz sentido, seja como for. A margem deve permanecer dentro do pai. Não mova o pai. Quem escreve essas regras.
Muhammad Umer 14/03
10
+2 para o último comentário. sério essa regra me incomoda. "60% do tempo funciona sempre" - são margens.
Casey Dwayne #
29
Eu concordo totalmente com os dois últimos comentadores. Isso é uma loucura. O que é interessante é que a adição de uma borda de 1px para o pai faz o trabalho direito, no entanto, isso significa que você tem uma borda ... se este é o comportamento esperado, então isso é ridículo
erdomester
1
Isso também pode ajudá-lo :) stackoverflow.com/questions/35337043/…
Bhojendra Rauniyar
5
Isso me lembra a regra padrão de tamanho de caixa: " Precisamos enviar uma caixa. A caixa não deve ter mais de 100 cm. Precisamos de 10 cm de preenchimento dentro da caixa para garantir que nosso conteúdo não quebre durante o transporte. Vamos fazer a caixa 120cm! "Que piada.
Nolonar

Respostas:

492

Encontrou uma alternativa em Elementos filho com margens nas DIVs. Você também pode adicionar:

.parent { overflow: auto; }

ou:

.parent { overflow: hidden; }

Isso evita o colapso das margens . Borda e preenchimento fazem o mesmo. Portanto, você também pode usar o seguinte para evitar um colapso na margem superior:

.parent {
    padding-top: 1px;
    margin-top: -1px;
}

Atualização por solicitação popular: todo o objetivo de reduzir as margens é lidar com o conteúdo textual. Por exemplo:

h1, h2, p, ul {
  margin-top: 1em;
  margin-bottom: 1em;
}
<h1>Title!</h1>
<div class="text">
  <h2>Title!</h2>
  <p>Paragraph</p>
</div>
<div class="text">
  <h2>Title!</h2>
  <p>Paragraph</p>
  <ul>
    <li>list item</li>
  </ul>
</div>

Como o navegador reduz as margens, o texto aparecerá como o esperado e as <div>tags do invólucro não influenciam as margens. Cada elemento garante espaçamento ao redor, mas o espaçamento não será dobrado. As margens do <h2>e <p>não serão adicionadas, mas deslizarão uma para a outra (elas entrarão em colapso). O mesmo acontece para o elemento <p>e <ul>.

Infelizmente, com designs modernos, essa idéia pode morder você quando você deseja explicitamente um contêiner. Isso é chamado de novo contexto de formatação de bloco no CSS speak. O overflowtruque ou margem lhe dará isso.

vdboor
fonte
41
Eu quero saber por que isso acontece, o que isso faz de bom para alguém. Que situação esse 'recurso' deveria ser.
Muhammad Umer 14/03
2
@ MuhammadUmer, bem, isso tem a ver com o conteúdo do texto. Por exemplo, uma série de <h2>, <p>, <ul>não vai conseguir lacunas estranhas ou margens "duplo" desta forma.
vdboor
7
Você poderia dar um exemplo? Digamos que eu tenho div como pano de fundo. Com h1, h2 ep nele. Agora eu quero mover h1 um pouco para baixo, para que não fique tão perto da borda acima da div de fundo, mas não expanda o próprio elemento h1. Eu acho que adicionar margem superior. O que é óbvio. mas quando faço isso, o fundo glorioso decide mudar com ele. Como isso é um recurso. Como isso ajuda no espaçamento entre h1, h2 e p. Ajude-me a ver o que você está dizendo.
Muhammad Umer
1
Eu adicionei um exemplo para você
vdboor 02/09
3
eu esperaria adicionar mais margem. colapsar margens é de longe a coisa mais irritante da minha carreira de desenvolvimento. se eu colocar 2 divs ao lado do outro com margin: 5px 10px;id esperar 2 divs 5 px do topo e 20 px entre eles e não 5 px do topo e 10 px entre eles. se eu quisesse 10 px entre eles, o id foi especificado margin: 5px 5px;. Eu sinceramente gostaria que houvesse uma regra raiz que eu pudesse colocar que parasse todas as margens em colapso. Eu odeio que eu tenho que dobrar o tamanho das margens no papel para fazê-los realmente fazer o que diabos eu quero na tela. e esta coisa topo ... o que é um desastre
JL Griffin
50

Esse é um comportamento normal (pelo menos entre as implementações do navegador). A margem não afeta a posição da criança em relação aos pais, a menos que os pais tenham preenchimento. Nesse caso, a maioria dos navegadores adicionará a margem da criança ao preenchimento dos pais.

Para obter o comportamento desejado, você precisa:

.child {
    margin-top: 0;
}

.parent {
    padding-top: 10px;
}
Ben James
fonte
3
Adicionando fronteira para o pai efetuará margem da criança também, tentar.parent {border: solid 1px;}
OKW
1
A margem não aumenta o preenchimento ... aplica-se separadamente. Mas o efeito visual é o mesmo.
Brilliand
1
E se você quiser uma margem superior ...? Não é realmente uma solução.
Fee
3
Como feeela disse - isso não é realmente uma solução se for necessária uma margem superior. A resposta do vdboor combina melhor.
Joey Morani
1
Existem várias soluções, você só precisa ser criativo o suficiente. Felicidades. :-)
Slavik Meltser
24

Embora todas as respostas resolvam o problema, elas vêm com trocas / ajustes / compromissos como

  • floats, Você tem a flutuar elementos
  • border-top, Isso empurra o pai pelo menos 1 px para baixo, que deve ser ajustado com a introdução de -1pxmargem no próprio elemento pai. Isso pode criar problemas quando o pai já possui margin-topunidades relativas.
  • padding-top, mesmo efeito que usar border-top
  • overflow: hidden, Não pode ser usado quando o pai deve exibir conteúdo excedente, como um menu suspenso
  • overflow: auto, Introduz barras de rolagem para o elemento pai que possui conteúdo intencionalmente excedente (como sombras ou triângulo da dica de ferramenta)

O problema pode ser resolvido usando pseudoelementos CSS3 da seguinte maneira

.parent::before {
  clear: both;
  content: "";
  display: table;
  margin-top: -1px;
  height: 0;
}

https://jsfiddle.net/hLgbyax5/1/

Ejaz
fonte
margin-top: -1pxparece ser desnecessário. Mas eu gosto disso.
Flimm
3
Na verdade, ambos margin-top: -1pxe height: 0parece desnecessário. Testado no Chrome. Mas a melhor solução.
NinjaFart
Esse método geralmente funciona, mas não respeitará a margem inferior do último elemento dentro do contêiner. Não é uma solução igual para transbordar: oculto; por exemplo.
Michael Giovanni Pumo
1
@MichaelGiovanniPumo, a resposta pode ser modificada para funcionar com a margem inferior do último elemento, usando.parent:after...
Ejaz
Definitivamente, essa é a resposta correta hoje em dia. Funciona perfeitamente (depois e antes), espero que as pessoas se atrevam a passar pelos outros!
fgblomqvist
13

adicionar estilo display:inline-blockao elemento filho

Атанас Димитров
fonte
9

o elemento pai não deve estar vazio pelo menos &nbsp;antes do elemento filho.

George SEDRA
fonte
2
sim, às vezes só isso pode ajudar ... ou melhor colocar algo como isto: <div style = 'width: 0; height: 0'> & nbsp; </ div>
Pigalev Pavel
7

Isto é o que funcionou para mim

.parent {
padding-top: 1px;
margin-top: -1px;
}

.child {
margin-top:260px;
}

http://jsfiddle.net/97fzwuxh/

erdomester
fonte
2

Descobri que, dentro do seu .css>, se você definir a propriedade display de um elemento div para bloquear em linha, isso resolverá o problema. e margem funcionará conforme o esperado.

vincent thorpe
fonte
2

Solução pura de CSS

Use o código a seguir para anexar um primeiro filho sem conteúdo à div que se move sem querer:

.parent:before
{content: '';position: relative;height: 0px;width: 0px;overflow: hidden;white-space: pre;}

A vantagem desse método é que você não precisa alterar o CSS de nenhum elemento existente e, portanto, tem um impacto mínimo no design. Além disso, o elemento adicionado é um pseudo-elemento, que não está na árvore DOM.

O suporte a pseudo-elementos é amplo: Firefox 3+, Safari 3+, Chrome 3+, Opera 10+ e IE 8+. Isso funcionará em qualquer navegador moderno (tenha cuidado com o mais novo ::before, que não é suportado no IE8).

Contexto

Se o primeiro filho de um elemento tiver um margin-top, o pai ajustará sua posição como uma forma de recolher margens redundantes. Por quê? É assim mesmo.

Dado o seguinte problema:

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}
</style>

<div class="parent"><!--This div moves 40px too-->
    <div class="child">Hello world!</div>
</div>

Você pode corrigi-lo adicionando um filho com conteúdo, como um espaço simples. Mas todos nós odiamos adicionar espaços para o que é um problema apenas de design. Portanto, use a white-spacepropriedade para falsificar conteúdo.

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}
.fix {position: relative;white-space: pre;height: 0px;width: 0px;overflow: hidden;}
</style>

<div class="parent"><!--This div won't move anymore-->
    <div class="fix"></div>
    <div class="child">Hello world!</div>
</div>

Onde position: relative;garante o posicionamento correto da correção. E white-space: pre;faz com que você não precise adicionar nenhum conteúdo - como um espaço em branco - à correção. E height: 0px;width: 0px;overflow: hidden;garante que você nunca verá a correção.

Pode ser necessário adicionar line-height: 0px;ou max-height: 0px;garantir que a altura seja realmente zero nos navegadores IE antigos (não tenho certeza). E, opcionalmente, você pode adicioná <!--dummy-->-lo em navegadores antigos do IE, se não funcionar.

Em resumo, você pode fazer tudo isso apenas com CSS (o que elimina a necessidade de adicionar um filho real à árvore DOM HTML):

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}

.parent:before {content: '';position: relative;height: 0px;width: 0px;overflow: hidden;white-space: pre;}
</style>

<div class="parent"><!--This div won't move anymore-->
    <div class="child">Hello world!</div>
</div>
Yeti
fonte
Use esta solução apenas se estiver desesperado e não puder definir CSS personalizado para os elementos existentes - caso contrário, use a solução real: set overflow: hidden;para o pai.
Yeti
2

Para impedir "Div parent", use a margem de "div child":
No parent use estes css:

  • Flutuador
  • Preenchimento
  • Fronteira
  • Transbordar
Bingo
fonte
1

Os marginelementos contidos .childestão em colapso.

<html>
<style type="text/css" media="screen">
    #parent {background:#dadada;}
    #child {background:red; margin-top:17px;}
</style>
<body>
<div id="parent">

    <p>&amp;</p>

    <div id="child">
        <p>&amp;</p>    
    </div>

</div>
</body>
</html>

Neste exemplo, pestá recebendo um margindos estilos padrão do navegador. O padrão do navegador font-sizeé normalmente 16 px. Ao ter um valor margin-topsuperior a 16px, #childvocê começa a perceber o movimento da posição.

25ª hora
fonte
1

Eu também tive esse problema, mas preferi evitar hacks de margens negativas, então coloquei um

<div class="supercontainer"></div>

ao redor de tudo que tem estofados em vez de margens. Claro que isso significa mais divite, mas é provavelmente a maneira mais limpa de fazer isso corretamente.

Zyl
fonte
1

Curiosamente, minha solução favorita para esse problema ainda não foi mencionada aqui: usando carros alegóricos.

html:

<div class="parent">
    <div class="child"></div>
</div>

css:

.parent{width:100px; height:100px;}
.child{float:left; margin-top:20px; width:50px; height:50px;}

veja aqui: http://codepen.io/anon/pen/Iphol

observe que, caso você precise de altura dinâmica no pai, ele também precisará flutuar; basta substituir height:100px;porfloat:left;

schellmax
fonte
1

Uma solução alternativa que encontrei antes de saber a resposta correta era adicionar uma borda transparente ao elemento pai.

Sua caixa usará pixels extras ...

.parent {
    border:1px solid transparent;
}
SandRock
fonte
0

Usar em topvez de margin-topé outra solução possível, se apropriado.

lamplightdev
fonte