Block Formatting Contexts in CSS

An older version of this blog is present on sitepoint.

A Block Formatting Context(BFC) is part of the visual CSS rendering of a web page in which block boxes are laid out. The positioning scheme to which it belongs is normal flow. According to W3C:

Floats, absolutely positioned elements, inline-blocks, table-cells, table-captions, and elements with ‘overflow’ other than ‘visible’ (except when that value has been propagated to the viewport) establish new block formatting contexts.

The above quote pretty much sums up how a block formatting context is formed. But lets redefine it in a way that is easier to understand. A block formatting context is an HTML box that satisfies at least one of the following conditions:

  • The value of float is not none
  • The value of position is neither static nor relative
  • The value of display is table-cell, table-caption, inline-block, flex, or inline-flex
  • The value of overflow is not visible.

Creating a Block Formatting Context

For example, look at the following HTML:

<div class="container">
Some Content here
</div>

A new block formatting context can be created by adding any one of the necessary CSS conditions like overflow: scroll, overflow: hidden, display: flex, float: left, or display: table to the container. Though any of the above mentioned conditions can create a block formatting context, there will also be some other effects like:

  • display: table may create problems in responsiveness
  • overflow: scroll may show unwanted scrollbars
  • float: left will push the element to the left, with other elements wrapping around it
  • overflow: hidden will clip elements that overflow

So whenever we are creating a new block formatting context, we choose the best condition based on our requirements. For uniformity, I have used overflow: hidden in all the examples given in this article.

.container {
overflow: hidden;
}

You are free to play with declarations other than overflow: hidden.

Alignment of Boxes in a Block Formatting Context

In a block formatting context, each box’s left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box’s line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).

Block Formatting Context

In simpler words, as we can see in the above diagram, all the boxes that belong to a block formatting context are aligned left (for left-to-right formatting) and their left outer edge touches the left edge of the containing block. In the last box we can see that even though there is a floated element (brown) on the left, the other element (green) still touches the left margin of the containing block. The principles about why this happens will be discussed below in the section on text wrapping.

A Block Formatting Context Causes Collapsing Margins

Lets consider an example, in order to understand this.

In the above diagram we consider a block formatting context having been created where the red box (a div) contains the two green siblings (p elements).

<div class="container">
<p>Sibling 1</p>
<p>Sibling 2</p>
</div>

And the corresponding CSS is:

.container {
background-color: red;
overflow: hidden; /* creates a block formatting context */
}
p {
background-color: lightgreen;
margin: 10px 0;
}

Ideally the margin between the two siblings should have been the sum of the margins of both elements (20px) but it’s actually 10px. This is known as collapsing margins. In a case where the margins of the siblings are different, then the higher margin will prevail.

Using a Block Formatting Context to Prevent Margin Collapse

Lets add a third sibling in the earlier example, so the HTML becomes:

<div class="container">
<p>Sibling 1</p>
<p>Sibling 2</p>
<p>Sibling 3</p>
</div>

With the corresponding CSS being:

.container {
background-color: red;
overflow: hidden; /* creates a block formatting context */
}

p {
background-color: lightgreen;
margin: 10px 0;
}

The result will be same as above, i.e. there will be a collapse and the three siblings will be separated by a vertical distance of 10px. This happens because all three p tags are the part of the same block formatting context.

Now lets modify the third sibling so that it’s part of a new block formatting context. Then the HTML becomes:

<div class="container">
<p>Sibling 1</p>
<p>Sibling 2</p>
<div class="newBFC">
<p>Sibling 3</p>
</div>
</div>

And the CSS:

.container {
background-color: red;
overflow: hidden; /* creates a block formatting context */
}
p {
margin: 10px 0;
background-color: lightgreen;
}
.newBFC {
overflow: hidden; /* creates new block formatting context */
}

Now there will be a difference in the output:

Since the second and third siblings belong to different formatting contexts, there won’t be any margin collapse between them, as evident in the following demo.

Using a Block Formatting Context to Contain Floats

Lets look at an example:

<div class="container">
<div>Sibling</div>
<div>Sibling</div>
</div>

With the CSS:

.container {
background-color: green;
}
.container div {
float: left;
background-color: lightgreen;
margin: 10px;
}

In the above case the container won’t have any height and it won’t contain the floated children. To solve this problem we establish a new block formatting context inside the container by adding overflow: hidden. The modified CSS becomes:

.container {
overflow: hidden; /* creates block formatting context */
background-color: green;
}
.container div {
float: left;
background-color: lightgreen;
margin: 10px;
}

Now the container will contain the floated siblings and its height will expand to contain its children, with the elements back in the normal flow of the page within this formatting context.

Using Block Formatting Contexts to Prevent Text Wrapping

First let us understand why the text wraps. For this we have to understand how the box model works when an element is floated. This is the part I left earlier while discussing the alignment in a block formatting context. Let us understand what is happening in Figure 1 in the diagram below:

The HTML for the diagram could be assumed as:

<div class="container">
<div class="floated">
Floated div
</div>
<p>
Quae hic ut ab perferendis sit quod architecto,
dolor debitis quam rem provident aspernatur tempora
expedita.
</p>
</div>

The whole black area in the above diagram denotes the p element. As we can see, the p element doesn’t shift but it goes under the floated element. The line boxes of the p element (referring to the lines of text) undergo a shift. Hence the line boxes narrow horizontally to make space for the floated element.

As the text increases, it will eventually wrap under the floated element because the line boxes no longer need to shift and hence a condition like Figure 1 appears. This explains how the paragraphs touch the left edge of the containing box even when a floated element is present and how the line boxes narrow to accommodate the floated element.

If we are able to shift the entire p element, then this wrapping problem will be solved.

Before going to the solution, let us recall again what the W3C spec says:

In a block formatting context, each box’s left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box’s line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).

According to this, if the p element establishes a new block formatting context then it will no longer touch the left edge of the container block. This can be achieved by simply adding overflow: hidden to the p element. This way creating a new block formatting context solves the problem of text wrapping around a floated object.

Using Block Formatting Contexts in Multi-column Layouts

Let’s use an example of a multi-column layout with 3 columns:

Here’s the HTML:

<div class="container">
<div class="column">column 1</div>
<div class="column">column 2</div>
<div class="column">column 3</div>
</div>

And the CSS:

.column {
width: 31.33%;
background-color: green;
float: left;
margin: 0 1%;
}

/* Establishing a new block formatting
context in the last column */
.column:last-child {
float: none;
overflow: hidden;
}

The result is in the CodePen demo:

Now even if the width of the container changes slightly, the layout will not break. Of course, this is not necessarily a good option for multi-column layouts, but it is one way to prevent the problem of the final column dropping. Flexbox would likely be a better solution in a case like this, but this should serve to illustrate how elements behave under these circumstances.

Conclusion

Lead Software Developer @ Anarock, https://riteshkr.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store