Madding and pargins — write maintainable CSS

I spent like two years using margins and padding the wrong way. The problem is so frequent among web developers, I've taken to calling them madding and pargins. People get them mixed up.

Let's take a look at what they actually do.

CSS box model

Basically, you have your context box, which holds child elements. Then there is padding, borders, and margins, all of which create space around the content box in different ways.

Padding keeps the background of the content box. So, if the content box has a black background, the padding will also have a black background.

Borders are meant to be decorative, but they technically don't have to be. They create space around the padding and have modifiers for things like dashed lines or dots.

Margins create space around the borders, meant to create space between elements.

But what if you don't care whether the background shows up or not? Maybe it's transparent. Do you use padding, or margins? Read on.

Margins can collapse. Did you know that?

Consider the following code.

<p>Hello world!</p>  
<p>This is another paragraph.</p>  
p {  
  margin-top: 20px;
  margin-bottom: 20px;
}

Now, how many pixels exist between the two paragraph elements? The first paragraph has 20px of margin on the bottom, and the second one has 20px of margin on the top, so... 40px?

The answer is 20px. Twenty pixels of space exist between the two paragraph elements.

This is because margins collapse. Meaning, when two vertical margins would touch, the largest of the two will be the amount of space between the elements. Try it out.

p {  
  margin-top: 20px;
  margin-bottom: 50px;
}

In this case, there will be 50px of space between the two elements, since 50px is the largest of the two.

You may have noticed, but this doesn't always happen. First of all, collapsing margins only happen vertically, not horizontally. Only margin-top and margin-bottom exhibit this effect. Next, it only happens within the same block formatting context. And what the hell is that, you may ask?

A block formatting context is a part of a visual CSS rendering of a Web page. It is the region in which the layout of block boxes occurs and in which floats interact with each other.

A block formatting context is created by one of the following:

  • the root element or something that contains it
  • floats (elements where float is not none)
  • absolutely positioned elements (elements where position is absolute or fixed)
  • inline-blocks (elements with display: inline-block)
  • table cells (elements with display: table-cell, which is the default for HTML table cells)
  • table captions (elements with display: table-caption, which is the default for HTML table captions)
  • block elements where overflow has a value other than visible
  • flex boxes (elements with display: flex or inline-flex)

See MDN's full article for more information.

If your margins aren't collapsing and you want them to be, nest your HTML differently so your elements don't establish new box formatting contexts. If you want to force a new box formatting context, you can put overflow: auto; on the parent element.

This behavior does not happen for padding. But it is extremely useful, and we should be taking advantage of it. Collapsing margins allow developers to create content elements that can be arranged in any order, and still maintain the correct spacing between them.

Margins on the tops, padding on the sides

I have adopted a practice of nearly always using margins on the top and bottom of elements, and padding on the sides.

That's right: my main content boxes have NO PADDING ON THE TOP OR BOTTOM. Let the child elements set their own spacing by using margins, and then set the content box to have overflow: auto; so it creates a new block formatting context.

I have done that here.

As you can see, my H2 goes right up to THE VERY TOP GODDAMN EDGE. There is no padding on the top or bottom of the content box! Only margins on the top and bottom of the children.

Collapsing margins allow developers to create content elements that can be arranged in any order, and still maintain the correct spacing between them.

This is way better for maintainability, since we can define each individual element's spacing separately, and then arrange them in any order. The correct spacing will always exist between elements.

It is especially pertinent when using a CMS like Wagtail or Apostrophe and you allow the editor to arrange the elements in any order. Using this method, you can arrange the elements in any order and it will always have the correct amount of space between elements.

But you should be thinking about your content in this way anyway, regardless of whether you're using a CMS.

My code looks like this.

<div class="box">  
  <h2>Join the Movement</h2>
  <!-- Other elements... -->
</div>  
.box {
  overflow: auto;
  padding: 0 10px;
}
h2 {  
  margin: 0.83em 0;
}

As you can see, .box has padding on the sides to constrain the elements, and each element defines its own margin-top and margin-bottom.

It's important to think critically about how we use our tools. I don't think this solution is the end-all, but it's one of the most effective tricks I've taught myself lately and now I build all my sites this way.