Margin-Top pousser le div externe vers le bas

126

J'ai un div d'en-tête comme premier élément de mon div wrapper, mais lorsque j'ajoute une marge supérieure à un h1 à l'intérieur du div d'en-tête, il pousse le div d'en-tête entier vers le bas. Je me rends compte que cela se produit chaque fois que j'applique une marge supérieure au premier élément visible d'une page.

Voici un exemple d'extrait de code. Merci!

div#header{
	width: 100%;
	background-color: #eee;
	position: relative;
}

div#header h1{
	text-align: center;
	width: 375px;
	height: 50px;
	margin: 50px auto;
	font-size: 220%;
	background: url('../../images/name_logo.png') no-repeat;
}
<div id="header">
	<h1>Title</h1>
	<ul id="navbar"></ul>
</div>

Danny
la source

Réponses:

193

mettre overflow:autodans le parent div
voir plus dans ce lien

Juan Pablo
la source
29
overflow:hiddenest mieux dans 90% des cas.
vsync
1
Pourquoi débordement: caché serait-il meilleur?
peterchon
5
@peterchon - parce que l'auto peut provoquer des barres de défilement
vsync
3
ne fonctionne plus, la réponse de @ SW4 dans ce lien est meilleure
am05mhz
1
overflow: hiddenou overflow: autopeuvent provoquer des effets secondaires indésirables, dont certains peuvent ne pas être observés à première vue. J'ai trouvé que changer marginpour paddingfaire l'affaire, comme le suggère la réponse ci-dessous. Je ne comprends toujours pas pourquoi tout le problème se produit, cependant.
Gilad Barner
34

Je n'ai pas d'explication solide sur pourquoi cela se produit, mais j'ai corrigé ce problème en changeant le top-marginen top-paddingou en ajoutant display: inline-blockau style d'élément.

EDIT: c'est ma théorie

J'ai le sentiment que cela a quelque chose à voir avec la façon dont les marges sont réduites (combinées).

à partir des marges réduites du W3C :

Dans cette spécification, l'expression marges de réduction signifie que les marges adjacentes (pas de contenu non vide, de remplissage ou de zone de bordure ou de dégagement les séparant) de deux ou plusieurs boîtes (qui peuvent être côte à côte ou imbriquées) se combinent pour former une seule marge .

Ma théorie est que puisque votre premier élément est à côté du corps, les deux marges se combinent et sont appliquées au corps: cela oblige le contenu du corps à commencer en dessous de la marge réduite appliquée conformément au modèle de boîte .

Il y a des situations où les marges ne se réduisent pas, ce qui pourrait valoir la peine de jouer avec (à partir de la réduction des marges ):

* floated elements
* absolutely positioned elements
* inline-block elements
* elements with overflow set to anything other than visible (They do not collapse margins with their children.)
* cleared elements (They do not collapse their top margins with their parent block’s bottom margin.)
* the root element
rêveur numérique
la source
3
De plus, le remplissage ou la bordure de l'élément avec une marge réduite (la marge intérieure) le dé-réduira.
Anonyme le
Cela a fonctionné pour moi - j'avais des éléments absolus (une liste déroulante) dans mon conteneur, donc débordement: auto ne fonctionnait pas.
mwilcox
17

Voici quelques-unes des façons d'éviter la réduction des marges entre les éléments parent-enfant. Utilisez celui qui correspond le mieux au reste de votre style:

  • Réglez displaysur autre que block.
  • Réglez floatsur autre que none.
  • Supprimez la marge et utilisez à la place padding. Par exemple, si vous en aviez margin-top: 10px, remplacez par padding-top: 10px;.
  • Retirez la marge, et utiliser au lieu position( absoluteou relative) avec des attributs top, bottometc. Par exemple , si vous aviez margin-top: 10px, remplacez -les par position: relative; top: 10px;.
  • Ajoutez un paddingou un borderdans le côté où les marges se réduisent, à l' élément parent . La bordure peut être 1px et transparente.
  • Défini overflowsur autre que visiblel' élément parent .
Jesús Carrera
la source
5

Je sais que c'est un vieux problème, je l'ai rencontré plusieurs fois. Le problème est que tous les correctifs ici sont des hacks qui auraient potentiellement des conséquences inattendues.

Tout d'abord, il y a une explication simple au problème racine. En raison du fonctionnement de la réduction des marges, si le premier élément à l'intérieur d'un conteneur a une marge supérieure, cette marge supérieure est effectivement appliquée au conteneur parent lui-même. Vous pouvez tester cela vous-même en procédant comme suit:

<div>
    <h1>Test</h1>
</div>

Dans un débogueur, ouvrez-le et passez la souris sur le div. Vous remarquerez que le div lui-même est en fait placé là où la marge supérieure de l'élément H1 s'arrête . Ce comportement est voulu par le navigateur.

Il y a donc une solution facile à cela sans avoir à recourir à d'étranges hacks, comme le font la plupart des messages ici (pas d'insultes intentionnelles, c'est juste la vérité) - revenez simplement à l'explication d'origine - ...if the first element inside a container has a top margin...- Suite à cela, vous auriez donc besoin le premier élément d'un conteneur à NE PAS avoir de marge supérieure. D'accord, mais comment faire cela sans ajouter d'éléments qui n'interfèrent pas sémantiquement avec votre document?

Facile! Pseudo-éléments! Vous pouvez le faire via une classe ou un mixin prédéfini. Ajoutez un :beforepseudo-élément:

CSS via une classe:

.top-margin-fix:before {   
    content: ' ';
    display: block;
    width: 100%;
    height: .0000001em;
}

Avec cela, en suivant l'exemple de balisage ci-dessus, vous modifierez votre div en tant que tel:

<div class="top-margin-fix">
    <h1>Test</h1>
</div>

Pourquoi ça marche?

Le premier élément d'un conteneur, s'il n'a pas de marge supérieure, définit la position du début de la marge supérieure de l'élément suivant. En ajoutant un :beforepseudo-élément, le navigateur ajoute en fait un élément non sémantique (en d'autres termes, bon pour le référencement) dans le conteneur parent avant votre premier élément.

Q. Pourquoi la hauteur: .0000001em?

A. Une hauteur est requise pour que le navigateur pousse l'élément de marge vers le bas. Cette hauteur est effectivement égale à zéro, mais elle vous permettra toujours d'ajouter un remplissage au conteneur parent lui-même. Puisqu'il est effectivement nul, cela n'aura pas non plus d'effet sur la disposition du conteneur. Belle.

Vous pouvez maintenant ajouter une classe (ou mieux, dans SASS / LESS, un mixin!) Pour résoudre ce problème au lieu d'ajouter des styles d'affichage étranges qui entraîneront des conséquences inattendues lorsque vous voulez faire d'autres choses avec vos éléments, en éliminant délibérément les marges sur les éléments et / ou le remplacer par un remplissage ou des styles de position / flottement étranges qui ne sont vraiment pas destinés à résoudre ce problème.

dudewad
la source
2
Le .0000001em est vraiment arrondi à zéro dans IE11, cassant votre correctif. Quand je le change en .01em, cela fonctionne.
Esger
1
J'imagine que .01em sera suffisant pour être encore effectivement nul. Bon point. Du côté positif, maintenant que nous sommes en 2018, beaucoup d'entre nous abandonneront bientôt le support pour IE11, en particulier avec l'annonce récente que MS construira à nouveau un nouveau navigateur (sauf cette fois, basé sur le chrome, ce qui signifie - théoriquement - ne sera pas totalement nul). : D
dudewad
2

display: flexfonctionnera dans ce cas. Donnez l'élément parent display: flex;, puis donnez une marge selon vos besoins à la h1balise.

Bijay
la source
0

Rencontrez ce problème aujourd'hui.

overflow: hidden n'a pas fonctionné comme prévu quand j'ai eu plus d'éléments suivis.

J'ai donc essayé de changer la propriété d'affichage de la div parent et j'ai display: flextravaillé !!!

J'espère que cela peut aider quelqu'un. :)

Libin
la source
0

L'ajout d'un petit peu de remplissage au sommet de l'élément parent peut résoudre ce problème.

.parent{
  padding-top: 0.01em;
}

Ceci est utile si vous avez besoin qu'un élément à l'intérieur du parent soit visible à l'extérieur de l'élément parent, comme si vous créez un effet de chevauchement.

adamspruijt
la source
0

Cela se produit en raison de l'effondrement des marges. Lorsque l'élément enfant touche la limite de l'élément parent et que l'un d'entre eux est appliqué avec des marges, alors:

  1. La marge la plus importante l'emportera (appliquée).

  2. si l'un d'entre eux a une marge, les deux partageront la même chose.

Solutions

  1. appliquer une bordure au parent qui sépare le parent et l'enfant.
  2. appliquer un remplissage au parent qui sépare le parent et l'enfant.
  3. appliquer le débordement plutôt que visible sur le parent.
  4. utiliser avant ou après pour créer un élément virtuel dans le div parent qui peut différer la marge appliquée de l'enfant et du parent.
  5. créer un élément html entre la marge appliquée enfant et le parent peut également les séparer.
Ishu
la source