Managing vertical margins in CSS

7th Apr, 2020

Achieving consistent vertical space between elements with CSS can be hard. Margins are usually to blame, but how can we make them more manageable?

Collapsing margins

One of the main sources of layout frustration is that vertical margins collapse. There are some exceptions to this, but that’s the general rule.

Rachel Andrew published a fantastic breakdown of how CSS margins work, where she states:

When margins collapse, they will combine so that the space between the two elements becomes the larger of the two margins. The smaller margin essentially ending up inside the larger one.

Collapsing margins are seen frequently when we have two block elements stacked on top of each other.

In the example below, we have two p elements with margin-top: 0.5em and margin-bottom: 0.5em:

See the Pen (@websmyth) on CodePen.

At a glance, it would seem the total amount of space between these elements is 1em (0.5em + 0.5em). But that isn’t the case because the margins collapse.

In our example, the margin-bottom of the first p combines with the margin-top of the second p. That creates a total margin of: 0.5em.

A hacky fix

Let’s say we wanted the gap between these elements to be 1em, how could we do that?

One solution might be to set one, or both of the vertical margins to 1em:

See the Pen (@websmyth) on CodePen.

That works and it gives us the desired spacing, but it’s hardly efficient: each pair of elements only uses three out of the four declared margin values.

Further problems arise when we start adding elements with different margin values into the mix. When applied across an entire site, it soon becomes difficult to know which margin values can be changed without breaking something.

Margin strategy

A better margin strategy is to set all vertical margins in one direction only: either margin-top or margin-bottom.

Declaring margin values in this way makes our code much more predictable. You no longer have to worry about the knock-on effect of a collapsed margin.

It also makes code maintenance easier: you can safely adjust a margin knowing that it will have the desired effect.

Returning to our example, that could be rewritten like this:

See the Pen (@websmyth) on CodePen.

Exceptions

There will of course be exceptions to this, but they should be exactly that: exceptions.

Since adopting this technique, I’ve significantly cut down the use of top and bottom margins on a single element.

Lobotomized Owls

Setting margins in a single direction is particularly effective when combined with Heydon Pickering’s Lobotomised Owl technique. The original artice is well-worth reading.

Pickering’s technique lets us set margin only between elements. That means we no longer have spare margin at the top or bottom of a stack of elements.

In our example above, we’ve used margin-top: 1em to provide the space between all p elements. This works, but the first p is not flush with the top of the parent container.

Below, I’ve added an article container with a blue border to demonstrate this:

See the Pen (@websmyth) on CodePen.

To make the first p flush with the top of the parent box, we would need to add:

p:first-child {
	margin-top: 0;
}

See the Pen (@websmyth) on CodePen.

Removing margin-top over an entire project can be verbose and difficult to maintain.

Pickering’s solution is to use the universal selector (*) combined with the adjacent selector (+), so that the margin is only applied between adjacent elements:

* + * {
	margin-top: 1em;
}

We could write p + p in our example, but the elegance of the universal selector is that it applies to all elements. That means we don’t need to guess which elements our content will need: we can write exceptions where necessary.

To further control where these margins are applied, we can limit this to direct child elements within parent containers.

In our example, that would look like this:

article > * + * {
	margin-top: 1em;
}

See the Pen (@websmyth) on CodePen.

Reducing margin headaches

The Lobotomized Owl technique is an extremely helpful and practical method of controlling vertical space.

I’d recommend reading Pickering’s original article on Lobotomized Owls.

Applying margins to the top and bottom of elements can create layout headaches and maintenance issues. When vertical margins are set in a single direction and combined with the Lobotomized Owl technique, many of these issues are resolved.