Are negative CSS margins bad practice?

Are negative CSS margins bad practice?

The negative CSS margin is a bit of a black sheep of the box model family. Unlike its siblings the negative padding and border – which are simply invalid – the negative margin is useful yet often misused.

So is using negative margins 'back practice'?

The short answer is no, as long as you are only using negative CSS margins to bring elements closer together than their box model properties would allow.

Since positive margins are used to bring box model objects away from each other, the canonical use case for negative margins is to remove the positional constraints applied by another element's content, padding, or border.

The downside of negative margins is they are difficult to debug and will make your CSS harder to read. The most often misuses of negative margins that I encounter is when it is used to make up for incorrect layouts elsewhere on the site. This is indeed bad practice.

So when should you use negative margins? Let's take a look at some examples.

Offset Padding

One common use case for negative margins is to remove the padding and border constraints applied by a parent element. Let's start with a card containing Keat's poem To Autumn:

We want to enlarge the title of the poem so it takes up the entire upper section of the card, but the size of the <h1> is constrained by the card's outer padding. Negative margins allow us to override the constraints:

You can achieve the same effect using absolute positioning – see below.

The Absolute positioning approach is significantly more brittle since it takes the element out of the document flow. Now we need to add more padding elsewhere on the page to compensate for the size of the title. Changing the size or content of the title now requires changing multiple lines of CSS to update card layout – the dreaded "multiple CSS tweaks for a small change".

Overlapping Boxes

Because negative margins bring elements closer together, it is perfect for creating overlapping elements.

Let's add a little emphasis to the Keat's name in our card and overlap it with card header to add emphasis:

This is a valid use case for negative margins since we are intentionally breaking out of the box model. We can similarly do this with absolute positioning:

Like the padding example, the absolute positioning method requires 2 changes when we make future changes: one to update the copy and another to update the offset to compensate for the copy. This makes our CSS more complex.

Break Out of Parent Container

The last example I want to look at is how negative margins can be used to change a parent component's content width constraint. Let's say we want to add a popover on hover with the author's bio, using absolute position so it doesn't take up document flow:

We see that popover content width is limited by its parent. This is an ugly look. We can set a fixed width for our popover, but the width is now static. With a short copy, this means lots of white space.

Instead of having a fixed width, we can use a negative margin on the child element to allow ample space for growth as the copy needs:

However, this is no longer the preferred way to achieve this effect with the introduction of CSS sizing 3 values min-content, max-content, and fit-content. To achieve this effect with modern browsers we can simply use width: max-content instead:

This is a cleaner, more readable approach that unfortunately does not work in Internet Explorer. Consider adding the negative margin trick as a fallback for IE.

Take-Aways

What should we take away from this exercise in negative CSS margins? A few things to note:

  1. Use negative CSS margins to overcome box model constraints inaccessible to layout algorithm changes.
  2. Negative margins can be easier to work with than their absolute positioned counterparts. By preserving the document flow, fewer layout tweaks are required on content and style changes.
  3. Negative margins can be hard to debug. Consider using CSS custom properties for negative margin values to make your code easier to read and to change.
.parent {
    --top-padding: 3rem;
    --border-width: 2px;
    padding-top: var(--top-padding);
    border-top: var(--border-width) 2px red;
}
.child {
    margin-top: calc(-1 * (var(--top-padding) + --border-width));
}

If you found this post helpful, please share it with others. You may also be interested in learning about how to use CSS custom properties to create style API or why Tailwind CSS is a big deal.

Follow me on Twitter @ItsTrueInTheory to get the latest blog updates or subscribe to email updates using the form below.

Show Comments