The Ultimate Guide to Why Your CSS Margins Aren’t Working

Introduction

CSS defines every element on an HTML page with a box called The Box Model. Alongside the element's content, padding, borders, and width, the margin is one of the properties CSS uses to define The Box Model.

Unlike other box model properties, CSS margins are not as straightforward as they may seem. They may not work, no matter how specific and error-free your styles may be.

In this guide, we will explore why your CSS margins may not work. We will cover four scenarios in which CSS margins fail to work. We will also explore different methods you can use to get your margins to work seamlessly every single time.

To understand this simple tutorial, you need a basic understanding of CSS and HTML. Use a basic code editor like CodePen or JsFiddle to follow.

Top and Bottom Margins Do Not Affect Inline Elements

Inline elements are HTML elements whose default CSS display property is display: inline. These include the <span> element, <code>, <bold>, <a>, and so on.

Top and bottom margins don't affect inline elements because such elements don't force the content before or after them onto new lines.

If you apply other vertical box-model-properties for example padding or border to an inline element, the padding or border will apply. But the box will overflow into its neighboring elements while keeping its content on the same line.

Additionally, the box will ignore any vertical margin you apply to it.

To understand this behavior, consider the example below.

HTML

We have a block element div followed by two inline span elements.

<!--Top and bottom margins do not affect inline elements -->
<section>
  <div class="block-element">Block Element</div>
  <span class="first-inline-element">First Inline Element</span>
  <span class="second-inline-element">Second Inline Element</span> 
</section>

CSS

The first span(.first-inline element) has padding in all directions. It also has margins in all directions except at the bottom.

/* CSS: Top and bottom margins do not affect inline elements */
.block-element {
  background-color: magenta;
  padding-bottom: 10px;
}
.first-inline-element {
  background-color: aqua;
  margin-right: 30px;
  margin-left: 50px;
  margin-top: 100px;/*This margin does not affect the element*/
  padding: 20px 30px 20px;
}
.second-inline-element {
  background-color: yellow;
}

RESULT

Notice that on the .first-inline-element span, both vertical and horizontal paddings work but because it’s inline, its padding forces the box to overflow into the .block-element div.

Additionally, applying a horizontal margin to the .first-inline-element span pushes the .second-inline-element span to the right but the top margin does not push the .block-element div upwards.

How to Get Your Margins to Work on Inline Elements

To get your vertical margins to work on inline elements, change their display property from inline to ‘inline-block’.

Alternatively, you can convert them into block elements if that decision doesn't break your layout.

Illustration

CSS

In the example above, adding the display: inline-block CSS property to the .first-inline element will get the margin-top of 100px to work.

/*To get your vertical margins to work on inline elements, 
change the element from an inline to an inline-block element.*/
.first-inline-element {
  background-color: lavender;
  margin-right: 30px;
  margin-left: 50px;
  margin-top: 100px;/*This margin works on the element*/
  padding: 20px 30px 20px;
  display:inline-block; /*Changing the element from inline to 
  inline-block will get its top margin to work*/
}

RESULT

Notice that the vertical margin between the First Inline Element and the Block Element works now.

Vertical Margins Collapse Between Block Elements

Sometimes, the vertical margins of block elements combine. This behavior is known as margin collapse.

CSS collapsible margins are another reason why your margins may not work. There are three scenarios in which CSS vertical margins collapse.

1. Top and Bottom Margins Collapse Between Two Adjacent Siblings

Whenever you have two adjacent block siblings in normal flow, the bottom margin of the first sibling collapses into(combines with) the top margin of the second sibling.

The resultant margin between them will be equal to the larger margin of the two siblings.

Consider the example below for a clear interpretation of this behavior.

HTML

We have a .parent section containing three .sibling divs.

<!--Top and bottom margins collapse between two adjacent siblings -->
<section class="parent">
  <div class="sibling">First Sibling</div>
  <div class="sibling">Second Sibling</div>
  <div class="sibling">Third Sibling</div>
</section>

CSS

The .sibling divs each have a top margin of 70px.

/*Top and bottom margins collapse between two adjacent siblings */
.parent {
  border: 1px solid purple;
}
.sibling{
  margin-top: 70px; 
  background-color: lavender;
}

RESULT

This margin works perfectly on all the divs as shown below.

The .sibling divs' behavior gets more interesting when we give them a bottom margin as well.

CSS

/*Top and bottom margins collapse between two adjacent siblings */
.sibling{
  margin-top: 70px; 
  Margin-bottom:30px; /*This margin only affects the third sibling*/
  background-color: lavender;
}

RESULT

When we apply a bottom margin of 30px to all the siblings, notice that it will only affect the third sibling.

The first and second siblings will remain unaffected. That’s because the bottom margin of 30px on the first and second divs will collapse(disappear) into the top margin of 70px on the second and third sibling divs respectively.

The resultant margin between the siblings will still be the larger margin of 70px.

Illustration:

How to Get Your Margins to Work Between Two Adjacent Siblings

To properly get your margins to work between two adjacent siblings, always set your largest margin between said siblings equal to your desired margin value.

A common practice is to apply margins in one direction on all elements. i.e., applying only margin-top on all siblings or margin-bottom, but not both.

For example:

In the code illustration above, if you want the space between the siblings always to be 100px, only set a bottom margin of 100px on all the siblings.

You can always apply padding to the parent container to add space between the parent and the first(top) sibling.

CSS

/* To get your vertical margins to work between adjacent siblings, 
apply your total margin only in one direction*/
.parent {
  border: 1px solid purple;
  Padding-top:100px; /* Adds space above the first sibling*/
}
.sibling{
  margin-bottom:100px; /*Applies margin in only one direction */
  background-color: lavender;
}

RESULT

We have equal spacing between all the siblings. We also have equal spacing between the parent and the first and third siblings.

2. The Top and Bottom Margins of Empty Block Elements Will Collapse into Each Other

If no inner text or content, padding, height, or min-height separates the margin-top from the margin-bottom of a block element –that is to say, if it’s empty – its top and bottom margins will collapse.

Still, the resultant margin on the box will be the larger value of the two margins.

You can observe this behavior in the illustration below:

HTML

We have a .parent section containing three divs. A .top div and a .bottom div, separated by an .empty div.

<!-- The top and bottom margins of empty block elements 
collapse into each other -->
<section class="parent">
  <div class="top">Top Div</div>
  <div class="empty"></div>
  <div class="bottom">Bottom Div</div>
</section>

CSS

The empty div has a top margin and a bottom margin, each of 30px.

/* The top and bottom margins of empty block elements 
collapse into each other */
.parent {
  border: 1px solid purple;
}
.top, .bottom{
  background-color: pink;
}
.empty {
  margin-top: 30px;
  margin-bottom: 30px;
}

RESULT

You will notice that the total space between the Top and bottom divs is only 30px, not 60px as expected.

How to Get Your Margins to Work on Empty Block Elements

Just like in the previous scenario, to get your margins to work properly on empty block elements, apply your total desired margin in only one direction. i.e. Only apply margin-top or margin-bottom but not both.

Alternatively, you can get your margins to work on an empty element by adding content between the top and bottom margins of your block element.

Content can be inner text, a 1px border, a padding, a height, or a minimum height.

Illustration:

In the above code example, adding a white 1px border on the empty div will get our margins to work without breaking the layout.

CSS

/* A simple trick you can use to get both top and 
bottom margins to work on empty block elements*/
.parent {
  border: 1px solid purple;
}
.top, .bottom{
  background-color: pink;
}
.empty {
  margin-top: 30px;
  margin-bottom: 30px;
  border: 1px solid white; /*Without breaking the layout, 
adding this border will get our top and bottom margins to 
work on empty block elements*/
}

RESULT

Adding a 1px white border gets both top and bottom margins to work on our empty div. The total space between the top and bottom divs is 60px.

3. Vertical Margins Collapse Between Parents and Their Immediate Descendants(First/Last Child Elements)

If no content separates them, the top margin of a first child, block descendant collapses into its parent's top margin.

That is, the top edge of the child will stack to the parent's top edge with no space between them. The child element's margin will collapse into the parent margin, appearing outside the parent.

Similarly, the bottom margin of the last child descendant will collapse into the bottom margin of its parent, appearing outside the parent.

The descendant's bottom edge will stack against the parent's without space between them.

Illustration:

HTML

We have a parent section containing four .descendant divs.

<!-- Vertical margins collapse between parents and their 
immediate descendants -->
<section class="parent">
  <div class="descendant">First(Immediate) Descendant</div>
  <div class="descendant">Second Descendant</div>
  <div class="descendant">Third Descendant</div>
  <div class="descendant">Last(Immediate) Descendant</div>
</section>

CSS

All the descendants have top and bottom margins each equal to 50px.

/* Vertical margins collapse between parents and their 
immediate descendants */
.parent {
  background-color: paleturquoise;

}
.descendant {
  border: 1px solid black;
  margin-top: 50px; /* This margin does not affect the First 
  Descendant element*/
  margin-bottom: 40px; /* This margin does not affect the 
  Last Descendant element*/
}

RESULT

Notice that the First Descendant and Last Descendant divs are unaffected by the top and bottom margins respectively.

That is because those margins collapse with(disappear into) the parent's top and bottom margins respectively, appearing outside the parent section.

How to Get Your Margins to Work Between Parents and First/Last Child Descendants

To get your margins to work between parents and their direct descendants, there are two measures you can take:

1. Add content between the parent's margin and its direct descendant's margin.

Add content between a parent's top margin and its first child's top to fix non-working margins between them.

Similarly, add content between a parent's bottom margin and its last descendant's bottom margin to fix non-working margins between them.

To add content between the parent and its direct descendants, without breaking your layout, add a border, small padding, height, or ‘min-height’ to the parent element.

Illustration:

CSS

Adding a 1px border to our .parent section gets our top and bottom margins to work on the first and last descendants respectively.

/*Add a 1px border on the parent to get vertical 
margins to work between the parent and its direct descendants*/
.parent {
  background-color: paleturquoise;
  border: 1px solid teal; /* This border gets vertical margins 
  to work between the parent and its direct descendants.*/ 

}
.descendant {
  border: 1px solid black;
  margin-top: 50px; /* This margin works on the First Descendant 
  element*/
  margin-bottom: 40px; /* This margin works on the Last Descendant 
  element*/
}

RESULT

2. Create a New Block Formatting Context on the Parent to Fix Non-working Margins Between a Parent and its Direct Descendants

Other than adding content between a parent and its direct descendants, to fix non-working margins on them, define a new Block Formatting Context(BFC) on the parent.

Simply put, all boxes in normal flow on an HTML page can either be inline or block boxes, but not both simultaneously.

Inline boxes form what is known as an inline formatting context and block boxes form a block formatting context(BFC). By default, the root <HTML> element creates a BFC.

To create a new block formatting context on an element, take it out of the normal flow of the HTML document using any of the following CSS tricks:

  1. Float the element using the CSS properties: float: left or float: right.

  2. Set the element’s position property to either position: absolute or position: fixed.

  3. Give the element the CSS overflow value other than visible or clip: e.g overflow: hidden or overflow: scroll.

  4. Give the element the CSS contain property and set its value to either contain: layout, content, or paint.

  5. Change the element’s display property to either one of these variants of the display: block property, that is; inline-block, flex, grid, table, table-cell, table-caption, table-row, table-row-group, inline-table, table-row-header, or flow-root.

That said, without breaking your layout, the easiest way to create a new block formatting context is by using the display:flow-root property on the parent element.

The above-mentioned property will get your vertical margins to work properly between a parent container and their first/last child descendants.

Illustration:

CSS

/*Define a New Block Formatting Context on the Parent to 
fix Non-working Margins Between a Parent and its Direct Descendants*/
.parent {
  background-color: paleturquoise; 
  Display: flow-root; /* By creating a new Block Formatting 
  context on the parent, this display property gets our margins 
  to work between the parent and its direct descendant */
}
.descendant {
  border: 1px solid black;
  margin-top: 50px; /* This margin works on the First Descendant 
  element*/
  margin-bottom: 40px; /* This margin works on the Last Descendant 
  element*/
}

RESULT

Final Thoughts

There are several reasons why your CSS vertical margins may not work. That said, before attempting random fixes for your code, it is important to first understand what’s causing the problem.

Check if your element is ‘inline’. In that case, changing its display to block or inline-block would get your margins to work.

If your elements are block elements, use the fixes discussed in this article to avoid collapsible margins between adjacent siblings, parents & direct descendants, and empty block elements.

30
Subscribe to my newsletter

Read articles from Assumpta Nalubowa directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Assumpta Nalubowa
Assumpta Nalubowa

I am a Front-End-Web, freelance Technical Writer. I write SEO-optimized web tutorials on HTML, CSS, JavaScript, and Git. If you'd like to work with me, you can contact me at assumptanalubowa[at]gmail[dot]com To read my essays on love and life, check out: https://medium.com/@assumptanalubowa