X

Les règles de l’effondrement de la marge


Introduction

En CSS, les marges adjacentes peuvent parfois se chevaucher. C’est ce qu’on appelle «l’effondrement des marges», et il a la réputation d’être assez ignoble.

Voici un exemple typique, impliquant deux paragraphes frères :

Instead of sitting 48px apart, their 24px margins merge together, occupying the same space!

This idea might sound simple, but if you’ve been writing CSS for a while, you’ve almost certainly been surprised when margins either don’t collapse, or they collapse in weird and unexpected ways. In real-world projects, all kinds of circumstances can complicate matters.

The good news is that once we understand the rules behind this notoriously-confusing mechanism, it becomes a lot clearer, and a lot less surprising ✨.

In this tutorial, we’re going to dive deep into the details and figure it out. No more being bewildered!

When margin-collapse was added to the CSS specification, the language designers made a curious choice: horizontal margins shouldn’t collapse.

In the early days, CSS wasn’t intended to be used for layouts. The people writing the spec were imagining headings and paragraphs, not columns and sidebars.

So that’s our first rule: only vertical margins collapse.

Here’s a live-editable example. If you’re using a desktop browser, pop open the developer tools and inspect the margins for yourself:

Code Playground

Résultat

Actualiser le volet des résultats

Il est assez courant d’utiliser le <br /> tag (un saut de ligne) pour augmenter l’espace entre les éléments de bloc.

Regrettably, this has an adverse effect on our margins:

The <br /> tag is invisible and empty, but any element between two others will block margins from collapsing. Elements need to be adjacent in the DOM for their margins to collapse.

What about when the margins are asymmetrical? Say, the top element wants 72px of space below, while the bottom element only needs 24px?

The bigger number wins.

This one feels intuitive if you think of margin as “personal space”. In this moment in history, it’s socially responsible to keep 6 feet apart. If someone wants even more space — say, 8 feet — we’ll need to keep 8 feet apart in order to satisfy both personal-space requirements.

Alright, here’s where it starts to get weird. Consider the following code:

We’re dropping our first paragraph into a containing <div>, but the margins will still collapse!

How can this be? Well, it turns out that many of us have a misconception about how margins work.

Margin is meant to increase the distance between siblings. It is not meant to increase the gap between a child and its parent’s bounding box; that’s what padding is for.

Margin will always try and increase distance between siblings, even if it means transferring margin to the parent element! In this case, the effect is the same as if we had applied the margin to the parent <div>, not the child <p>.

“But that can’t be!”, I can hear you saying. “I’ve used margin before to increase the distance between the parent and the first child!”

There are some conditions that must be satisfied in order for the margin to be transferred to the parent (and collapsed):

  • No other elements in-between (see earlier rule, about the <br>).

  • The parent element doesn’t have a height set.

  • The parent element doesn’t have any padding or border along the relevant edge.

That last condition is really common, so let’s look at a quick example. In this case, our nested child can’t combine margin with the next paragraph, because the parent has some padding in the way:

You can think of padding/border as a sort of wall; if it sits between two margins, they can’t collapse, because there’s a wall in the way. The width doesn’t matter, either; even 1px of padding will interfere with margin collapse.

So far, all the examples we’ve seen involve adjacent opposite margins: the bottom of one element overlaps with the top of the next element.

Surprisingly, margins can collapse even in the same direction.

Here’s what this looks like in code:

You can think of this as an extension of the previous rule. The child margin is getting “absorbed” into the parent margin. The two are combining, and are subject to the same rules of margin-collapse we’ve seen so far (eg. the biggest one wins).

This can lead to big surprises. For example, check out this common frustration:

Code Playground

Résultat

Actualiser le volet des résultats

Dans ce scénario, vous pouvez vous attendre à ce que les deux sections se touchent, avec la marge appliquée à l’intérieur de chaque conteneur :

Paragraphe un

Paragraphe deux

Cela semble être une hypothèse raisonnable, puisque le <section>s n’ont aucune marge du tout! L’intention semble être d’augmenter l’espace dans le haut de chaque case, pour donner aux paragraphes un peu de répit.

L’ennui c’est que La marge de 0px est toujours une marge réductible. Chaque section a une marge supérieure de 0px, et elle est combinée avec la marge supérieure de 32px sur le paragraphe. Puisque 32px est le plus grand des deux, il gagne.

L’effondrement des marges ne se limite pas à seulement deux marges ! Dans cet exemple, 4 marges distinctes occupent le même espace :

Il est difficile de voir ce qui se passe, mais c’est essentiellement une combinaison des règles précédentes :

  • Les frères et sœurs peuvent combiner des marges adjacentes (si le premier élément a une marge inférieure et le second une marge supérieure)

  • Un parent et un enfant peuvent combiner des marges dans le même sens

Chaque frère a un enfant qui contribue une marge de même direction.

Le voici, en code. Utilisez les devtools pour afficher chaque marge de manière isolée :

Aire de jeux codée

Résultat

Actualiser le volet des résultats

L’espace entre nos <header> et <section> a 4 marges distinctes en compétition pour occuper cet espace !

  • Le header veut de l’espace en dessous de lui

  • Le h1 dans le header a une marge inférieure, qui s’effondre avec son parent

  • Le section sous le header veut de l’espace au dessus de lui

  • Le p dans le section a une marge supérieure, qui s’effondre avec son parent

En fin de compte, le paragraphe a la plus grande marge cumulée, donc il gagne, et 40 pixels séparent le header et section.

Enfin, nous avons un autre facteur à prendre en compte : les marges négatives.

Les marges négatives permettent de réduire l’espace entre deux éléments. Cela nous permet de tirer un enfant en dehors de la boîte englobante de son parent ou de réduire l’espace entre les frères et sœurs jusqu’à ce qu’ils se chevauchent.

Comment les marges négatives s’effondrent-elles ? Eh bien, c’est en fait assez similaire aux positifs! Les marges négatives partageront un espace, et la taille de cet espace est déterminée par la marge négative la plus significative. Dans cet exemple, les éléments se chevauchent de 75px, puisque la marge la plus négative (-75px) était plus importante que l’autre (-25px).

Qu’en est-il lorsque les marges négatives et positives sont mélangées ? Dans ce cas, les chiffres sont ajoutés ensemble. Dans cet exemple, la marge négative de -25px et la marge positive de 25px s’annulent et n’ont aucun effet, puisque -25px + 25px est égal à 0.

Pourquoi voudrions-nous appliquer des marges qui n’ont aucun effet ?! Eh bien, parfois vous ne contrôlez pas l’une des deux marges. Peut-être que cela vient d’un style hérité ou qu’il est étroitement intégré à un composant. En appliquant une marge négative inverse au parent, vous pouvez “annuler” une marge.

Bien sûr, ce n’est pas idéal. Mieux vaut supprimer les marges indésirables que d’en rajouter encore ! Mais cette solution hacky peut être une bouée de sauvetage dans certaines situations.

Nous sommes allés assez loin dans les mauvaises herbes ici, et nous avons encore une chose à regarder. C’est le “boss final” de ce sujet, l’aboutissement de toutes les règles que nous avons vues jusqu’à présent.

Que se passe-t-il si nous avons plusieurs marges en concurrence pour le même espace, et que certaines sont négatives ?

S’il y a plus de 2 marges impliquées, l’algorithme ressemble à ceci :

  • Trouver la plus grande marge positive

  • Trouvez le plus grand marge négative

  • Additionnez ces deux nombres ensemble

Voici un exemple dans le code. Jetez un coup d’œil dans les devtools pour voir comment tout cela fonctionne :

Aire de jeux codée

Résultat

Actualiser le volet des résultats

Dans cet exemple, notre marge positive la plus importante est de 30 pixels. Notre marge négative la plus importante est de -20px. Par conséquent, nous nous retrouvons avec 10px de marge réalisée, puisque nous additionnons les valeurs positives et négatives ensemble.

(Pas d’illustration 3D pour celle-ci – honnêtement, elle était trop occupée et chaotique pour offrir beaucoup de clarté 😅)

Jusqu’à présent, tous les exemples que nous avons vus supposaient que nous étions « in-flow » ; nous ne repositionnons pas les choses avec Grid ou Flexbox.

Lorsque les éléments sont alignés avec Grid ou Flexbox, ou retirés du flux (par exemple, flottants, positionnement absolu), les marges ne s’effondreront jamais. Cela peut être surprenant lorsqu’il est combiné avec certaines techniques, comme ma mise en page Full Bleed. Dans ces cas, il vaut mieux utiliser gap au lieu de marge.

En fait, il y a un mouvement croissant de développeurs optant pour des composants de mise en page au lieu de la marge. Je pense que les composants de mise en page sont géniaux, mais je reconnais également que la marge est universel. Même si vous décidez de l’abandonner, il y a de fortes chances que vous deviez encore travailler sur des produits qui l’utilisent, ou avec des développeurs qui le font.

Ouf, ça faisait beaucoup de règles !

Avec un peu de pratique, cependant, ce genre de choses devient une seconde nature. Bientôt, vous saurez comment cela fonctionne, vous n’aurez même pas à y penser.

Cet article interactif a été extrait de mon prochain cours CSS, CSS pour les développeurs JavaScript. Dans le cours, vous construisez une intuition en jouant à un mini-jeu de type puzzle et vous vous entraînez en créant des mises en page dans des défis guidés par vidéo.

Ça va aussi bien au-delà effondrement de la marge – nous couvrons tout ce que vous devez savoir pour devenir un expert CSS éblouissant. Vérifiez-le, si vous êtes intéressé!

Je suis curieux de savoir si ce tutoriel vous a aidé à consolider votre compréhension de l’effondrement des marges !

Voici un rapide sondage de style Twitter qui me permettra de savoir si ce tutoriel a été efficace ou non :

Si vous avez répondu “Non”, cela vous dérangerait-il tendre la main sur Twitter et me faire savoir quelles parties prêtaient à confusion ? Ce matériel fera partie de mon cours payant, j’ai donc hâte de le rendre aussi bon que possible 🙏

Dernière mise à jour

9 juin 2021