La marge sur l'élément enfant déplace l'élément parent

415

J'ai un div( parent ) qui en contient un autre div( enfant ). Parent est le premier élément bodysans style CSS particulier. Quand je mets

.child
{
    margin-top: 10px;
}

Le résultat final est que le haut de mon enfant est toujours aligné avec le parent. Au lieu que l'enfant soit déplacé de 10 pixels vers le bas, mon parent se déplace de 10 pixels vers le bas.

Mon DOCTYPEest réglé sur XHTML Transitional.

Qu'est-ce que j'oublie ici?

modifier 1
Mon parent doit avoir des dimensions strictement définies car il a un arrière-plan qui doit être affiché en dessous de haut en bas (pixel parfait). Ainsi , la mise en marges verticales il est un pas aller .

edit 2
Ce comportement est le même sur FF, IE et CR.

Robert Koritnik
la source
188
ce comportement n'a aucun sens. La marge est supposée rester à l'intérieur du parent. Ne pas déplacer le parent. Qui écrit ces règles.
Muhammad Umer
10
+2 pour le dernier commentaire. sérieusement, cette règle me dérange. "60% du temps ça marche à chaque fois" - c'est des marges.
Casey Dwayne
29
Je suis totalement d'accord avec les deux derniers commentateurs. C'est insensé. Ce qui est intéressant, c'est que l'ajout d'une bordure 1px au parent le fait fonctionner correctement, mais cela signifie que vous avez une bordure ... si tel est le comportement attendu, alors c'est ridicule
erdomester
1
Cela peut également vous aider :) stackoverflow.com/questions/35337043/…
Bhojendra Rauniyar
5
Cela me rappelle la règle de dimensionnement par défaut de la boîte: " Nous devons expédier une boîte. La boîte ne doit pas dépasser 100 cm. Nous avons besoin de 10 cm de rembourrage à l'intérieur de la boîte pour garantir que notre contenu ne se casse pas pendant l'expédition. la boite 120cm! "Quelle blague.
Nolonar

Réponses:

492

Vous avez trouvé une alternative dans les éléments enfants avec des marges dans les DIV. Vous pouvez également ajouter:

.parent { overflow: auto; }

ou:

.parent { overflow: hidden; }

Cela empêche les marges de s'effondrer . La bordure et le rembourrage font de même. Par conséquent, vous pouvez également utiliser les éléments suivants pour éviter un effondrement de la marge supérieure:

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

Mise à jour par demande populaire: L'intérêt de réduire les marges est de gérer le contenu textuel. Par exemple:

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>

Étant donné que le navigateur réduit les marges, le texte apparaîtra comme prévu et les <div>balises wrapper n'influencent pas les marges. Chaque élément garantit un espacement autour de lui, mais l'espacement ne sera pas doublé. Les marges du <h2>et <p>ne s'additionnent pas, mais se glissent l'une dans l'autre (elles s'effondrent). La même chose se produit pour l' élément <p>et <ul>.

Malheureusement, avec des designs modernes, cette idée peut vous mordre lorsque vous voulez explicitement un conteneur. C'est ce qu'on appelle un nouveau contexte de formatage de bloc dans CSS parler. L' overflowastuce ou la marge vous le donnera.

vdboor
la source
41
je veux savoir pourquoi cela arrive quel bien cela fait à personne. Quelle situation cette «fonctionnalité» était censée être?
Muhammad Umer
2
@MuhammadUmer, eh bien cela a à voir avec le contenu du texte. Par exemple, une série de <h2>, <p>, <ul>ne se étranges lacunes ou des marges « doubles » de cette façon.
vdboor
7
Pourriez-vous donner un exemple. Disons que j'ai div en arrière-plan. Avec h1, h2 et p dedans. Maintenant, je veux déplacer un peu h1 pour qu'il ne soit pas si près du bord supérieur de la division d'arrière-plan, mais pas pour développer l'élément h1 lui-même. Je pense que j'ajoute une marge supérieure. Ce qui est évident. mais quand je le fais, le fond glorieux décide de descendre avec lui. Comment c'est une fonctionnalité. Comment cela aide à espacer entre h1, h2 et p. Aidez-moi à voir ce que vous dites.
Muhammad Umer
1
J'ai ajouté un exemple pour vous
vdboor
3
je m'attendrais à ce qu'il ajoute plus de marge. l'effondrement des marges est de loin la chose la plus ennuyeuse de ma carrière de développement. si je mets 2 div à côté de l'autre avec margin: 5px 10px;id attendez-vous à 2 divs 5 px du haut et 20 px entre eux pas 5 px du haut et 10 px entre eux. si je voulais 10 px entre eux, je l'ai spécifié margin: 5px 5px;. je souhaite sincèrement qu'il y ait une règle racine que je pourrais placer qui empêcherait l'effondrement de toute marge. Je déteste devoir doubler la taille des marges sur papier pour les amener à faire ce que je veux à l'écran. et ce truc top ... quel désastre
JL Griffin
50

Il s'agit d'un comportement normal (au moins parmi les implémentations de navigateur). La marge n'affecte pas la position de l'enfant par rapport à son parent, sauf si le parent a un rembourrage, auquel cas la plupart des navigateurs ajouteront alors la marge de l'enfant au rembourrage du parent.

Pour obtenir le comportement que vous souhaitez, vous avez besoin de:

.child {
    margin-top: 0;
}

.parent {
    padding-top: 10px;
}
Ben James
la source
3
Ajouter une bordure au parent affectera également la marge de l'enfant, essayez.parent {border: solid 1px;}
okw
1
La marge n'ajoute rien au rembourrage ... elle s'applique séparément. Mais l'effet visuel est le même.
Brilliand
1
Et si vous voulez une marge supérieure…? Pas vraiment une solution.
feeela
3
Comme l'a dit feeela - ce n'est pas vraiment une solution si une marge supérieure est requise. La réponse de vdboor convient mieux.
Joey Morani
1
Il existe de nombreuses solutions, il vous suffit d'être suffisamment créatif. À votre santé. :-)
Slavik Meltser
24

Bien que toutes les réponses résolvent le problème, mais elles s'accompagnent de compromis / ajustements / compromis comme

  • floats, Vous devez faire flotter les éléments
  • border-top, Cela pousse le parent au moins 1px vers le bas, qui doit ensuite être ajusté en introduisant une -1pxmarge dans l'élément parent lui-même. Cela peut créer des problèmes lorsque le parent a déjà margin-topdes unités relatives.
  • padding-top, même effet que l'utilisation border-top
  • overflow: hidden, Ne peut pas être utilisé lorsque le parent doit afficher un contenu débordant, comme un menu déroulant
  • overflow: auto, Introduit des barres de défilement pour l'élément parent qui a (intentionnellement) du contenu débordant (comme des ombres ou un triangle de l'info-bulle)

Le problème peut être résolu en utilisant les pseudo-éléments CSS3 comme suit

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

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

Ejaz
la source
margin-top: -1pxsemble inutile. Mais j'aime ça.
Flimm
3
En fait, les deux margin-top: -1pxet height: 0semble inutile. Testé dans Chrome. Mais la meilleure solution.
NinjaFart
Cette méthode fonctionne principalement, mais ne respectera pas la marge inférieure du dernier élément du conteneur. Ce n'est pas une solution égale pour déborder: caché; par exemple.
Michael Giovanni Pumo
1
@MichaelGiovanniPumo la réponse peut être modifiée pour fonctionner avec la marge inférieure du dernier élément en utilisant.parent:after...
Ejaz
C'est certainement la bonne réponse de nos jours. Fonctionne parfaitement (mettez-le après et avant), j'espère que les gens oseront défiler les autres!
fgblomqvist
13

ajouter du style display:inline-blockà l'élément enfant

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

l'élément parent ne doit pas être vide au moins placé &nbsp;avant l'élément enfant.

George SEDRA
la source
2
oui, parfois seulement cela peut aider ... ou mieux mettre quelque chose comme ceci: <div style = 'width: 0; height: 0'> & nbsp; </div>
Pigalev Pavel
7

C'est ce qui a fonctionné pour moi

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

.child {
margin-top:260px;
}

http://jsfiddle.net/97fzwuxh/

erdomester
la source
2

Je découvre que, à l'intérieur de votre .css> si vous définissez la propriété d'affichage d'un élément div sur inline-block, cela résout le problème. et la marge fonctionnera comme prévu.

vincent thorpe
la source
2

Solution soignée CSS uniquement

Utilisez le code suivant pour ajouter un premier enfant sans contenu à la div qui se déplace involontairement:

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

L'avantage de cette méthode est que vous n'avez pas besoin de modifier le CSS d'un élément existant et qu'elle a donc un impact minimal sur la conception. À côté de cela, l'élément qui est ajouté est un pseudo-élément, qui n'est pas dans l'arbre DOM.

La prise en charge des pseudo-éléments est très répandue: Firefox 3+, Safari 3+, Chrome 3+, Opera 10+ et IE 8+. Cela fonctionnera dans n'importe quel navigateur moderne (soyez prudent avec le plus récent ::before, qui n'est pas pris en charge dans IE8).

Le contexte

Si le premier enfant d'un élément a un margin-top, le parent ajustera sa position pour réduire les marges redondantes. Pourquoi? C'est comme ça.

Étant donné le problème suivant:

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

Vous pouvez le corriger en ajoutant un enfant avec du contenu, tel qu'un simple espace. Mais nous détestons tous ajouter des espaces pour ce qui est un problème de conception uniquement. Par conséquent, utilisez la white-spacepropriété pour simuler du contenu.

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

position: relative;assure un positionnement correct du correctif. Et white-space: pre;vous évite d'ajouter du contenu - comme un espace blanc - au correctif. Et height: 0px;width: 0px;overflow: hidden;s'assure que vous ne verrez jamais le correctif.

Vous devrez peut-être ajouter line-height: 0px;ou max-height: 0px;vous assurer que la hauteur est réellement nulle dans les anciens navigateurs IE (je ne suis pas sûr). Et éventuellement, vous pouvez l'ajouter <!--dummy-->dans les anciens navigateurs IE, si cela ne fonctionne pas.

En bref, vous pouvez faire tout cela avec seulement CSS (ce qui supprime la nécessité d'ajouter un enfant réel à l'arborescence 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
la source
N'utilisez cette solution que si vous êtes désespéré et que vous ne pouvez pas définir de CSS personnalisé pour les éléments existants - sinon utilisez la vraie solution: définir overflow: hidden;pour le parent.
Yeti
2

Pour empêcher "Div parent", utilisez la marge de "div child":
Dans parent, utilisez ces CSS:

  • Flotte
  • Rembourrage
  • Frontière
  • Débordement
bingo
la source
1

Les marginéléments contenus à l'intérieur .childs'effondrent.

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

Dans cet exemple, preçoit un margindes styles par défaut du navigateur. La valeur par défaut du navigateur font-sizeest généralement de 16 pixels. En ayant un margin-topde plus de 16px sur #childvous commencez à remarquer son mouvement de position.

25thhour
la source
1

J'ai aussi eu ce problème mais j'ai préféré éviter les hacks de marges négatives, j'ai donc mis un

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

autour de tout ce qui a des rembourrages au lieu de marges. Bien sûr, cela signifie plus de divitis, mais c'est probablement le moyen le plus propre de le faire correctement.

Zyl
la source
1

Fait intéressant, ma solution préférée à ce problème n'est pas encore mentionnée ici: l'utilisation de flotteurs.

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

voir ici: http://codepen.io/anon/pen/Iphol

notez que si vous avez besoin d'une hauteur dynamique sur le parent, il doit également flotter, remplacez simplement height:100px;parfloat:left;

schellmax
la source
1

Une solution alternative que j'ai trouvée avant de connaître la bonne réponse était d'ajouter une bordure transparente à l'élément parent.

Votre boîte utilisera cependant des pixels supplémentaires ...

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

Utiliser à la topplace de margin-topest une autre solution possible, le cas échéant.

lamplightdev
la source