Comment désactiver l'effondrement des marges?

203

Existe-t-il un moyen de désactiver complètement l'effondrement des marges? Les seules solutions que j'ai trouvées (sous le nom de "décollement") impliquent l'utilisation d'une bordure 1px ou d'un remplissage 1px. Je trouve cela inacceptable: le pixel superflu complique les calculs sans raison valable. Existe-t-il un moyen plus raisonnable de désactiver cet effondrement des marges?

kjo
la source
4
Utilisez la mise en page Flex ou Grid, où la réduction de la marge n'existe pas: stackoverflow.com/a/46496701/3597276
Michael Benjamin
Donnez simplement une valeur aux éléments margin-bottommais laissez margin-top0.
Dan Bray
J'ai créé un package pour faciliter le calcul: npmjs.com/package/collapsed-margin
Owen M

Réponses:

255

Il existe deux principaux types d'effondrement des marges:

  • Réduction des marges entre les éléments adjacents
  • Réduction des marges entre les éléments parent et enfant

L'utilisation d'un rembourrage ou d'une bordure empêchera l'effondrement uniquement dans ce dernier cas. En outre, toute valeur overflowdifférente de sa valeur par défaut ( visible) appliquée au parent empêchera l'effondrement. Ainsi, les deux overflow: autoet overflow: hiddenauront le même effet. La seule différence lors de l'utilisation hiddenest peut-être la conséquence inattendue de masquer le contenu si le parent a une hauteur fixe.

Les autres propriétés qui, une fois appliquées au parent, peuvent aider à résoudre ce problème sont les suivantes:

  • float: left / right
  • position: absolute
  • display: inline-block / flex

Vous pouvez tous les tester ici: http://jsfiddle.net/XB9wX/1/ .

Je dois ajouter que, comme d'habitude, Internet Explorer est l'exception. Plus précisément, dans IE 7, les marges ne se réduisent pas lorsqu'un type de disposition est spécifié pour l'élément parent, tel que width.

Sources: article de Sitepoint Collapsing Margins

hqcasanova
la source
1
notez que le rembourrage peut également affecter cela si sa valeur n'est pas nulle
Mladen Janjetovic
3
Notez que cela overflow: autopeut faire apparaître des barres de défilement dans l'élément parent, plutôt que de laisser déborder le contenu déborder selon overflow: visible.
Leo
'overflow: auto' ne semble pas fonctionner dans Chrome v44.
tkane2000
3
Merci pour l'affichage: le bloc en ligne, cela m'a sauvé :)
alexcasalboni
3
Toute valeur flexdifférente de sa valeur par défaut désactivera également l'effondrement des marges
Oly
60

Vous pouvez également utiliser le bon vieux micro clearfix pour cela.

#container:before, #container:after{
    content: ' ';
    display: table;
}

Voir le violon mis à jour: http://jsfiddle.net/XB9wX/97/

Blackgrid
la source
J'ai transformé ma réponse en wiki communautaire. N'hésitez pas à l'étendre avec votre réponse. Merci.
hqcasanova
3
Je ne comprends pas, quand je regarde cet exemple, les marges s'effondrent (seulement 10px d'espace vertical entre les divs au lieu de 20px)
Andy
1
Cela aide uniquement à supprimer l'effondrement entre les frères et sœurs auxquels ce correctif est appliqué. J'ai bifurqué l'exemple pour le démontrer: jsfiddle.net/dpyuyg07 --- et même ce n'est pas toute l'histoire. Il supprime uniquement l'effondrement des marges résultant des enfants des éléments auxquels vous avez appliqué ce correctif. Si vous ajoutiez une marge sur le conteneur lui-même, les marges s'effondreraient toujours, ce qui peut être vu dans cette fourchette: jsfiddle.net/oew7qsjx
NicBright
4
Je peux le dire encore plus précisément: la méthode clearfix empêche uniquement l'effondrement des marges entre parents et enfants. Cela n'affecte pas l'effondrement entre frères et sœurs adjacents.
NicBright
Je pense que je comprends maintenant la tendance de Bootstrap à remplir le DOM avec les éléments :beforeet :after. J'ai maintenant ajouté cette règle à mon stylesheet: div:before, div:after{content: ' '; display: table;}. Fantastique. Soudain, les choses commencent à se comporter comme prévu.
Stijn de Witt
60

Une astuce intéressante pour désactiver l'effondrement des marges qui n'a aucun impact visuel, à ma connaissance, consiste à définir le remplissage du parent sur 0.05px:

.parentClass {
    padding: 0.05px;
}

Le rembourrage n'est plus 0, donc l'effondrement ne se produira plus, mais en même temps, le rembourrage est suffisamment petit pour que visuellement il arrondisse à 0.

Si un autre remplissage est souhaité, appliquez-le uniquement à la "direction" dans laquelle la réduction de la marge n'est pas souhaitée, par exemple padding-top: 0.05px;.

Exemple de travail:

.noCollapse {
  padding: 0.05px;
}

.parent {
  background-color: red;
  width: 150px;
}

.children {
  margin-top: 50px;

  background-color: lime;      
  width: 100px;
  height: 100px;
}
<h3>Border collapsing</h3>
<div class="parent">
  <div class="children">
  </div>
</div>

<h3>No border collapsing</h3>
<div class="parent noCollapse">
  <div class="children">
  </div>
</div>

Modifier: a changé la valeur de 0.1à 0.05. Comme Chris Morgan l'a mentionné dans un commentaire ci-dessous, et à partir de ce petit test , il semble qu'en effet Firefox prenne 0.1pxen compte le rembourrage. Cependant, 0.05pxsemble faire l'affaire.

Nicu Surdu
la source
2
Ceci est ma solution préférée. Vous pouvez même l'inclure comme style par défaut. Pourquoi pas? *{padding-top:0.1px}. Sommes-nous sûrs que cela fonctionne dans tous les navigateurs?
Nick Manning
Jusqu'à présent, cela a plutôt bien fonctionné pour moi, mais je ne prétends pas l'avoir testé à fond dans la plupart des navigateurs.
Nicu Surdu
2
Très belle solution, elle semble fonctionner comme prévu sur la plupart des navigateurs. Merci de le partager!
wiredolphin
1
Ceci est une solution dodgy car il n'ajouter des pixels supplémentaires dans diverses circonstances, en raison des écrans et des calculs de sous - pixels de haut DPI. (Firefox a fait une disposition en sous-pixels depuis des lustres, je crois que d'autres navigateurs ont relativement récemment emboîté le pas.)
Chris Morgan
0.05pxsemble toujours être un choix spécifique, pas un numéro aléatoire de navigateur, je préfère 0.01px.
Volker E.
22

overflow:hidden empêche l'effondrement des marges mais n'est pas exempt d'effets secondaires - à savoir qu'il ... cache le débordement.

En dehors de cela et de ce que vous avez mentionné, il vous suffit d'apprendre en direct et d'apprendre pour ce jour quand ils sont réellement utiles (tous les 3 à 5 ans).

Litek
la source
J'ai transformé ma réponse en wiki communautaire. Je pense que j'ai couvert l'effet secondaire que vous avez mentionné dans les deux dernières lignes du deuxième paragraphe: La seule différence lors de l'utilisation de masqué est peut-être la conséquence involontaire de masquer le contenu si le parent a une hauteur fixe . Mais si vous pensez que cela nécessite des éclaircissements, n'hésitez pas à contribuer. Merci.
hqcasanova
7
overflow: autoest bon à utiliser pour empêcher le débordement caché et toujours empêcher l'effondrement des marges.
Gavin
@Gavin, overflow:auto;ma zone de contenu a gagné une barre de défilement sur certaines pages.
Reed
13

En fait, il y en a un qui fonctionne parfaitement:

affichage: flex; flex-direction: colonne;

aussi longtemps que vous pouvez vivre avec un support uniquement IE10 et plus

.container {
  display: flex;
  flex-direction: column;
    background: #ddd;
    width: 15em;
}

.square {
    margin: 15px;
    height: 3em;
    background: yellow;
}
<div class="container">
    <div class="square"></div>
    <div class="square"></div>
    <div class="square"></div>
</div>
<div class="container">
    <div class="square"></div>
    <div class="square"></div>
    <div class="square"></div>
</div>

Daniel Koster
la source
Pour que cela fonctionne comme une solution générique, il faut ajouter un supplément <div>dans le .container, sinon le .containercontrôlera le modèle de boîte de ses enfants. Par exemple, les éléments en ligne deviendront des éléments de bloc pleine largeur; s'ils ont des marges, ceux-ci seront également réduits.
zupa
9

Chaque navigateur basé sur webkit doit prendre en charge les propriétés -webkit-margin-collapse. Il existe également des sous-propriétés pour le définir uniquement pour la marge supérieure ou inférieure. Vous pouvez lui donner les valeurs collapse (par défaut), discard (définit la marge à 0 s'il y a une marge voisine) et distinct (empêche la marge de s'effondrer).

J'ai testé que cela fonctionne sur les versions 2014 de Chrome et Safari. Malheureusement, je ne pense pas que cela serait pris en charge dans IE car il n'est pas basé sur le webkit.

Lisez la référence CSS d'Apple Safari pour une explication complète.

Si vous consultez la page des extensions webkit CSS de Mozilla , ils répertorient ces propriétés comme propriétaires et recommandent de ne pas les utiliser. En effet, ils n'entreront probablement pas dans le CSS standard de sitôt et seuls les navigateurs Webkit les prendront en charge.

Dan Carter
la source
C'est bien car cela nous aide à corriger une incohérence dans la façon dont Safari et Chrome traitent les marges.
bjudson
8

Je sais que c'est un très ancien article, mais je voulais juste dire que l'utilisation de flexbox sur un élément parent désactiverait l'effondrement de la marge pour ses éléments enfants.

Genzo
la source
Non seulement pour ses éléments enfants - il empêche également l'effondrement de la marge entre le parent et le premier et le dernier enfant.
Sven Marnach
2

J'ai eu un problème similaire avec l'effondrement de la marge parce que le parent s'est positionmis à relatif. Voici la liste des commandes que vous pouvez utiliser pour désactiver la réduction des marges.

VOICI AIRE DE JEUX POUR TESTER

Essayez simplement d'assigner n'importe quelle parent-fix*classe à l' div.containerélément, ou n'importe quelle classe children-fix*à div.margin. Choisissez celui qui correspond le mieux à vos besoins.

Quand

  • la réduction de la marge est désactivée , div.absoluteun arrière-plan rouge sera positionné tout en haut de la page.
  • la marge s'effondre div.absolute sera positionnée à la même coordonnée Y quediv.margin

html, body { margin: 0; padding: 0; }

.container {
  width: 100%;
  position: relative;
}

.absolute {
  position: absolute;
  top: 0;
  left: 50px;
  right: 50px;
  height: 100px;
  border: 5px solid #F00;
  background-color: rgba(255, 0, 0, 0.5);
}

.margin {
  width: 100%;
  height: 20px;
  background-color: #444;
  margin-top: 50px;
  color: #FFF;
}

/* Here are some examples on how to disable margin 
   collapsing from within parent (.container) */
.parent-fix1 { padding-top: 1px; }
.parent-fix2 { border: 1px solid rgba(0,0,0, 0);}
.parent-fix3 { overflow: auto;}
.parent-fix4 { float: left;}
.parent-fix5 { display: inline-block; }
.parent-fix6 { position: absolute; }
.parent-fix7 { display: flex; }
.parent-fix8 { -webkit-margin-collapse: separate; }
.parent-fix9:before {  content: ' '; display: table; }

/* Here are some examples on how to disable margin 
   collapsing from within children (.margin) */
.children-fix1 { float: left; }
.children-fix2 { display: inline-block; }
<div class="container parent-fix1">
  <div class="margin children-fix">margin</div>
  <div class="absolute"></div>
</div>

Voici jsFiddle avec un exemple que vous pouvez éditer

Buksy
la source
1

Dans un navigateur plus récent (à l'exception d'IE11), une solution simple pour empêcher l'effondrement de la marge parent-enfant consiste à utiliser display: flow-root. Cependant, vous auriez toujours besoin d'autres techniques pour empêcher l'effondrement des éléments adjacents.

DEMO (avant)

.parent {
  background-color: grey;
}

.child {
  height: 16px;
  margin-top: 16px;
  margin-bottom: 16px;
  background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>

DEMO (après)

.parent {
  display: flow-root;
  background-color: grey;
}

.child {
  height: 16px;
  margin-top: 16px;
  margin-bottom: 16px;
  background-color: blue;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>

Chuanqi Sun
la source
0

Pour votre information, vous pouvez utiliser la grille mais avec des effets secondaires :)

.parent {
  display: grid
}
Whisher
la source