Ultimate Guide to non-working CSS margins

Category:

Sometimes you're styling some HTML elements with CSS and there seems to be a margin between the elements that you never defined. This article covers most cases why css margins are not working the way you expect them to be.

#Whitespaces between inline-blocks

If you put two inline-block elements next to each other in your HTML code, you need to make sure that there are no whitespaces between the closing and opening tags. Otherwise, as the elements are inline, they act like normal text elements where you would also expect to have a "margin" between your elements where a whitespace occurs.

The fix is to remove the spaces/newlines such that the opening and closing tags are immediately next to each other:

<span id="one"></span><span id="two"></span>

If you want to keep some formatting structure, you can use comments to remove the whitespaces:

   <span id="one"></span><!--
--><span id="two"></span>

#Inline Element Vertical Alignment

Whenever you have an inline element which is followed by a block element (or any element rendered in a new line), there will be a vertical space between these two. This effect is most noticeable for inline-images, like <svg> elements which are inline by default. This has to do with where in the current line the element is positioned. If not specified otherwise, inline elements are vertically aligned to the parent's baseline.

The fix is to vertically lower the element lower with for instance:

svg {
  vertical-align: middle;
}

#Collapsing Margins of Block Elements

The third way you can see margins between elements that you never defined has to do with something called Collapsing Margins:

Top and bottom margins of blocks are sometimes combined (collapsed) into a single margin whose size is the largest of the margins combined into it, a behavior known as margin collapsing.

The idea is that if you have several paragraphs and some other elements before or after them, and you want to have exactly 20px of margin between them, you can just define both margin-top: 20px; and margin-bot: 20px;. This way, there will always be a space of 20px between a paragraph and any element, even between adjacent paragraphs, because the top and bot margin between them collapses into a single one of 20px. Unfortunately, this behavior is often more of an annoyance you have to work around instead of something useful.

Besides collapsing margins between two adjacent elements, there are two other cases how collapsing margins can occur, but the most common one is between a parent and its first child:

For example, you want to wrap a heading into a div while leaving some space between the div's upper border and the heading by defining a margin-top: 20px on the heading. However, instead of the h2 moving down, the whole div moves down by 20px instead:

This happens because the div has no border, and no padding defined, and the CSS specification states to collapse the two top margins into a single one of the parent. (The same happens with bottom margins.)

There are several ways to circumvent margin collapsing:

  • Set a border or a (fake) padding on div:

    div {
      padding: 0.1px;
    }
  • Use padding instead of margin to adjust the child:

    h2 {
      padding-top: 20px;
    }
  • Collapsing margins only happens with block elements, so you can define div to be an inline-block to prevent it:

    div {
      display: inline-block;
    }
  • Defining a different overflow value also disables it:

    div {
      overflow: auto;
    }
  • Position your div absolute:

    div {
      position: absolute;
    }

These are the main issues why a space may appear somewhere you didn't expect, but once you aware of how inline elements are positioned and that collapsing margins exists, they are usually easy to fix.