Pourquoi ce style CSS margin-top ne fonctionne-t-il pas?

321

J'essaie d'ajouter des valeurs de marge sur un div à l'intérieur d'un autre div. Tout fonctionne bien sauf la valeur supérieure, il semble être ignoré. Mais pourquoi?

Ce que j'attendais:
Ce que j'attendais avec marge: 50px 50px 50px 50px;

Ce que j'obtiens:
Ce que j'obtiens avec marge: 50px 50px 50px 50px;

Code:

#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>

W3Schools n'a aucune explication pour expliquer pourquoi la marge se comporte de cette façon.

jamietelin
la source
4
avez-vous essayé de faire flotter l'intérieur?
Coq
6
hum .. Avec float:left;ça marche ... mais pourquoi est-ce nécessaire. Je ne veux pas qu'il flotte. Et pourquoi la marge pour gauche / droite fonctionne-t-elle?
jamietelin
44
Bienvenue dans le monde amusant de l'algorithme d'effondrement des marges CSS!
GordonM
10
W3Schools vs W3CDocs ... Je pense que nous avons un gagnant. : D
enderskill
15
jsFiddle de celui-ci, pour sauver le prochain gars 25 secondes jsfiddle.net/kLeu9
CodyBugstein

Réponses:

454

Vous voyez en fait la marge supérieure de l' #innerélément s'effondrer dans le bord supérieur de l' #outerélément, ne laissant que le#outer marge intacte (bien qu'elle ne soit pas affichée dans vos images). Les bords supérieurs des deux boîtes sont alignés l'un contre l'autre car leurs marges sont égales.

Voici les points pertinents de la spécification W3C:

8.3.1 Réduire les marges

En CSS, les marges adjacentes de deux ou plusieurs boîtes (qui peuvent ou non être des frères et sœurs) peuvent se combiner pour former une seule marge. Les marges qui se combinent de cette façon sont censées s'effondrer , et la marge combinée résultante est appelée une marge effondrée .

Les marges verticales adjacentes s'effondrent [...]

Deux marges sont contiguës si et seulement si:

  • les deux appartiennent à des boîtes de niveau bloc in-flow qui participent au même contexte de formatage de bloc
  • pas de boîtes de ligne, pas de dégagement, pas de rembourrage et pas de bordure les séparent
  • les deux appartiennent à des bords de boîte adjacents verticalement, c'est-à-dire qu'ils forment l'une des paires suivantes:
    • marge supérieure d'une boîte et marge supérieure de son premier enfant entrant

Vous pouvez effectuer l'une des opérations suivantes pour empêcher la marge de s'effondrer:

La raison pour laquelle les options ci-dessus empêchent la marge de s'effondrer est la suivante:

  • Les marges entre une boîte flottante et toute autre boîte ne s'effondrent pas (pas même entre un flotteur et ses enfants entrants).
  • Les marges des éléments qui établissent de nouveaux contextes de mise en forme de bloc (tels que les flottants et les éléments avec un «débordement» autre que «visible») ne s'effondrent pas avec leurs enfants entrants.
  • Les marges des boîtes de blocs en ligne ne s'effondrent pas (pas même avec leurs enfants entrants).

Les marges gauche et droite se comportent comme prévu car:

Les marges horizontales ne s'effondrent jamais.

BoltClock
la source
2
Cette réponse est géniale! Juste quelque chose à ajouter. Votre citation de w3c le dit mais je ne m'en suis rendu compte que maintenant. Donc, pour être clair pour les autres, vous pouvez également donner une bordure à #outer.
driechel
Le lien dans Floating semble rompu.
EP
@episanty: C'est ce qui se produit lorsque vous créez un lien vers un commentaire. Non lié.
BoltClock
Je sais - je voulais juste vous le faire savoir. Puisque vous êtes ♦ -activé, j'ai pensé que vous voudriez peut-être ressusciter le commentaire - ou modifier votre message en conséquence. Merci pour la bonne réponse, au fait.
EP
92

Essayez d'utiliser display: inline-block;sur le div intérieur.

#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
la source
6
Bonne réponse. Il serait préférable d'expliquer pourquoi cette modification résout le problème.
JohnFx
1
Ok, c'est bizarre! Pourquoi ça marche? Quelle est l'explication logique de pourquoi cela ne fonctionne pas comme on pourrait s'y attendre. La marge gauche / droite fonctionne sans display:inline-block;. En outre, lorsque vous utilisez display:inline-block;, vous perdez la largeur de 100% sur la div.
jamietelin
3
le basculer sur inline-block force le navigateur à réévaluer la taille du div après son placement et d'autres règles sont appliquées.
Coq
Je l'ai essayé pour mon problème, j'ai fait un effet d'escalier.
Jonny
1
display:inline-blocktravaillé pour moi. Merci beaucoup.
starkeen
24

Ce que @BoltClock a mentionné est assez solide. Et ici, je veux juste ajouter plusieurs autres solutions à ce problème. vérifiez cette marge w3c_collapsing . Les parties vertes sont la pensée potentielle de la façon dont ce problème peut être résolu.

Solution 1

Les marges entre une boîte flottante et toute autre boîte ne s'effondrent pas (pas même entre un flotteur et ses enfants entrants).

cela signifie que je peux ajouter float:leftà l'un #outerou à #inner demo1 .

notez également que floatcela invaliderait la automarge.

Solution 2

Les marges des éléments qui établissent de nouveaux contextes de mise en forme de bloc (tels que les flottants et les éléments avec un «débordement» autre que «visible») ne s'effondrent pas avec leurs enfants entrants.

autre que visible, mettons overflow: hiddendans #outer. Et cette façon semble assez simple et décente. Je l'aime.

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

Solution 3

Les marges des boîtes absolument positionnées ne s'effondrent pas (même pas avec leurs enfants entrants).

#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;
}

ces deux méthodes vont rompre le flux normal de div

Solution 4

Les marges des boîtes de blocs en ligne ne s'effondrent pas (pas même avec leurs enfants entrants).

est le même que @enderskill

Solution 5

La marge inférieure d'un élément de niveau bloc en flux s'effondre toujours avec la marge supérieure de son frère frère au niveau bloc suivant, sauf si ce frère a un dégagement.

Cela n'a pas beaucoup de travail à faire avec la question car c'est la marge qui s'effondre entre frères et sœurs. cela signifie généralement si un top-box a margin-bottom: 30pxet un frère a margin-top: 10px. La marge totale entre eux est 30pxau lieu de 40px.

Solution 6

La marge supérieure d'un élément de bloc entrant s'effondre avec la première marge supérieure de son enfant au niveau du bloc entrant si l'élément n'a pas de bordure supérieure, pas de rembourrage supérieur et que l'enfant n'a aucun dégagement.

C'est très intéressant et je peux juste ajouter une ligne de bordure supérieure

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

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

}

Et <div>est également au niveau du bloc par défaut, vous n'avez donc pas à le déclarer exprès. Désolé de ne pas pouvoir publier plus de 2 liens et images en raison de ma réputation de novice. Au moins, vous savez d'où vient le problème la prochaine fois que vous verrez quelque chose de similaire.

Qiang
la source
14

Je ne sais pas pourquoi ce que vous avez ne fonctionne pas, mais vous pouvez ajouter

overflow: auto;

à la div extérieure.

Brandon
la source
Beaucoup de solutions différentes à ce problème. Merci! Cette réponse combinée avec la réponse de @ BoltClock fournit de bonnes informations sur les raisons pour lesquelles cette solution fonctionne.
jamietelin
12

Si vous ajoutez du rembourrage #outer, cela fonctionne.

Démo

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
    padding-top:1px;
}
bibliothèque
la source
11

Je ne sais pas exactement pourquoi, mais en changeant le CSS interne en

display:inline-block;

semble fonctionner;

harriyott
la source
3

Ne répond pas au "pourquoi" (doit être quelque chose avec une marge qui s'effondre), mais semble que la façon la plus simple / la plus logique de faire ce que vous essayez de faire serait d' ajouterpadding-top simplement à la div externe :

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

Note mineure - il ne devrait pas être nécessaire de définir un div à display:block;moins qu'il y ait quelque chose d'autre dans votre code lui disant de ne pas être bloqué.

Dave
la source
3

essaye ça:

#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/

Bonne chance

Mustafa M Jalal
la source
2

Je suppose que la définition de la propriété position du div #inner sur relative peut également aider à obtenir l'effet. Mais de toute façon, j'ai essayé le code original collé dans la question sur IE9 et le dernier Google Chrome et ils donnent déjà l'effet souhaitable sans aucune modification.

viditkothari
la source
2

Utilisation padding-top:50px pour div externe. Quelque chose comme ça:

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

Remarque: le rembourrage augmentera la taille de votre div. Dans ce cas, si la taille de votre div est importante, je veux dire si elle doit avoir une hauteur spécifique. diminuer la hauteur de 50 px:

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

Avez-vous essayé! Important avant tout, cela forcera tout:

margin:50px 50px 50px 50px !important;
atgr24869
la source
-1

Juste pour une solution rapide, essayez d'enrouler vos éléments enfants dans un divélément comme celui-ci -

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

La marge de innerdiv ne s'effondrera pas en raison du remplissage 1pxentre outeret innerdiv. Donc, logiquement, vous aurez 1pxplus d'espace avec la marge de innerdiv existante .

Mithilesh Tipkari
la source