Try โ€‚โ€‰HackMD

The case for .space

When CSS was introduced in 1996, one of the first features was the concept of margins, borders and padding. Over the years a lot of useful stuff got added. But margins, borders and padding are still here, mostly as initially designed.

However, for years webdesigners have been struggling with margins, and white space in general. The problem in short is, how do you create re-usable components with predictable white space, regardless of the contents of such components?

Let me show you a concrete example:

<div class="ds-box"> Contents of a box </div>

Which looks like this:

Contents of a box

The contents of the box are too close to its border. So I'll add some padding:

Contents of a box

This works well. Now let me change the content a bit:

A heading

with some content

As you see, a lot of extra white space has been added at the top and bottom. For normal text this is fine and expected. Extra white space above a heading adds more distance to the text above. This makes it clear that the heading is part of a new section of content.

But inside the box you don't need this extra space. It is usually better for all of these boxes to have a similar white space, regardless of the content.

Enter the lobotomized owl.

One trick designers have used is called the lobotomized owl. It looks like this:

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

This set of CSS rules removes the top margin of all elements, and re-introduces a standard top margin for all elements that have a previous sibling.

So in the case of our box, the results are:

A heading

with some content

This works for the heading, but the paragraph still adds a bottom margin. Since we've standardized the margin-top, lets remove the bottom margin for all elements:

A heading

with some content

And voila. Uniform white space around the content of the box.

But now the problems start. What happens if we add an image inside the box, before the heading and float it left?

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

A heading

with some more content

The image is the first child element of the box, so its margin is set to 0. But now the heading has a previous sibling, the image, and its margin-top is set to 1em.

You can work around this by moving the image inside the heading. But there are many other cases where the lobotomized owl (* + *) selector won't help you. I've been using it for quite some time and I've always had to add extra exceptions to the CSS of projects that used it.

The main problem is, I think, that this trick disables a feature of the webbrowser that isn't well understood, but is vital for correctly rendering text: margin collapse.

Margin collapse

Below is an example of a margin collapse in action - or well, emulated here. The yellow background is the margin of the heading, the blue background shows the margin of the paragraph. Between the heading and the paragraph, the colors overlap, because the margins overlap.

This is referred to as the margins collapsing.

A heading

A paragraph

The bottom margin of the heading is slightly larger than the top margin of the paragraph. So the top margin of the paragraph is fully collapsed. The collapsed margin between the elements becomes the size of whichever margin is bigger.

This isn't just the case for siblings. It also works when an element with a margin is contained inside another element, like this:

<h2>A heading</h2> <div> <p>A paragraph</p> </div>

As long as the <div> doesn't have padding or a border. There are some more exceptions, but these two are the most common.

The top margin of the paragraph is automatically applied to the <div>, where it is again collapsed with the bottom margin of the heading. Below is a visual example:

A heading

A paragraph

The purple line is the edge of the div element. The margin of the paragraph extends outside this edge. Note however, that this effect is gone whenever you add a border or padding to the div.

The example shows the top and bottom margin collapsing, but not the left or right. That is because those margins never collapse. Only the top and bottom margins have this behaviour. This makes sense, since it was designed for the normal flow of text in a webpage.

Enter .space

So lets use collapsing margins to fix the space issues we have with our box.

.space { margin: 2rem; }
<div class="ds-box"> <div class="space"> <h2>A heading</h2> <p>A paragraph</p> </div> </div>

A heading

A paragraph

I've added an extra wrapper with the class space. This adds a margin around the content, but within the ds-box component. The margin of space is larger than both the top margin of the heading and the bottom margin of the paragraph. Because of this, both those margins collapse over the space margin and disappear.

And let's add that floating image back again:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

A heading

with some more content

And now the white space is still consistent!

So at the cost of one extra HTML element, the ds-box component is much more robust. You don't need to add extra CSS exceptions when you change the content of the box component. And you can re-use the space element in any other component you design. This has the added benefit of having consistent spacing in all your components.

There are some things to consider though. For one, the space margins must be larger than the largest margin of any piece of content you add inside it. So if you really need just a tiny bit of white space, you'll have to go back to the lobotomized owl again. The modern design trend of large amounts of white space helps, however.

Another problem is that some modern display modes, e.g. flex and grid, don't use collapsing margins. If you need to use those and a consistent white space, you should add a space container inside each area inside a grid or flexbox container. Or you can lobotomize an owl again.

The last two years I've been using a space container in most of my CSS work. Only very rarely have I needed to fix white space issues. In general the problem has just disappeared. I hope this trick can help you get more done with less CSS as well!

Auke van Slooten

auke@muze.nl