How Does the CSS Block Formatting Context Work

How does the CSS Block Formatting Context work?

Block Formatting Contexts

Floats, absolutely positioned
elements, block containers (such as
inline-blocks, table-cells, and
table-captions) that are not block
boxes, and block boxes with 'overflow'
other than 'visible' (except when that
value has been propagated to the
viewport) establish new block formatting contexts for their contents.

With my bold, it's the establish bit that is important

What this means is that the element you use overflow (anything other than visible) or float or inline-block..etc on becomes responsible for the layout of its child elements. It's the child elements which are then "contained", whether that's floats or collapsing margins they should be wholly contained by their bounding parent.

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)

What the above line means:

Because a box can only be rectangular and not irregular shaped this means a new block formatting context between two floats (or even beside one) will not wrap around neighbouring side floats. The inner, child boxes can only extend as far as to touch their parents left (or right in RTL) edge. It's this behaviour that's useful for columnar style layouts. The main use of it however is to stop floats, say in a "main content" div, actually clearing floated side columns, i.e. floats that appear earlier in the source code.


Float Clearance

In normal circumstances floats are supposed to clear all previous floated elements, that's previously floated in the whole source code, not just your displayed "column"
The telling quote from the "float clearance specs" is:

This property indicates which sides of
an element's box(es) may not be
adjacent to an earlier floating box.
The 'clear' property does not consider
floats inside the element itself or in other block formatting contexts

So say you have a three column layout where the left and right columns are floated left and right respectively, the side columns are now in new Block Formatting Contexts, because they are floated (remember float is also one of the properties that establish a new BFC), so you can happily float list elements inside them and they only clear floats which are already inside the side columns they no longer care about floats previously in the source code


To make the main content a new Block Formatting Context or not?

Now that middle column, you can simply margin it from both sides so that it appears to sit neatly between the two side floated columns and take the remaining width, a common way to get desired width if the centre column is "fluid" - which will be fine until you need to use floats/clearance inside your content div (a common occurrence for those using "clearfix" hacks or templates including them)

Take this very simple code:

#left-col {  border: 1px solid #000;  width: 180px;  float: left;}#right-col {  border: 1px solid #000;  width: 180px;  float: right;  height: 200px;}#content {  background: #eee;  margin: 0 200px;}.floated {  float: right;  width: 180px;  height: 100px;  background: #dad;}
<div id="left-col">left column</div><div id="right-col">right column</div>
<div id="content"> <h3>Main Content</h3> <p>Lorem ipsum etc..</p> <div class="floated">this a floated box</div> <div class="floated">this a floated box</div></div>

What exactly is a formatting context?

A formatting context is not really an area. It's more a state of a box that defines the set of layout rules that apply to itself and its participant boxes.

Who is responsible for establishing formatting context for `body` element?

the body element acts as block container box.

No, it doesn't. We can easily proove it by using a float element:

.float {
height:50px;
width:50px;
background:red;
float:left;
}


body {
border:2px solid blue;
}

html {
border:2px solid green
}
<div class="float"></div> some text here

When does a box establish an inline formatting context?

To answer your question, I reread Section 9.2.1 of the CSS 2.1 spec.

Based on my reading, you have your answer: the inline formatting context is triggered when a block container box contains only inline elements.

In contrast to a block formatting context that can be triggered explicitly (for example, setting overflow: hidden to a block-level element), an inline formatting context cannot be triggered explicitly.

Inline formatting contexts appear to always exist as descendant block boxes within a "principal block-level box", and these descendant block boxes may be anonymous.

I offer the following description as a mental model for understanding block/inline formatting contexts.

A block-level element (e.g. a <div>) fulfills two responsibilities: one, positioning, and two, content formatting.

When dealing with positioning, a block-level element acts as a "block-level box".

When dealing with formatting, a block-level element acts as a "block container box".

Acting as a "block-level box", the block-element behaves according to the type of positioning (static, absolute, relative, fixed) specified by the position property.

Acting as a "block container box", the block-element establishes a block-formatting context if the block-element has at least one child block-level element. If all the child elements are inline-level boxes, then an inline-formatting context is established.

If the "block container box" contains text and block elements, then the text is treated as being contained in one or more anonymous block-level boxes, and a block-formatting context is established.

Aside

The CSS spec is not exactly light reading. I have reread Chapters 9 and 10 several times and I have yet to come up with a plain-English translation.

What formatting context applies to elements that don't create their own?

Put simply, every block sits in a formatting context. Blocks that have no special properties (e.g. divs with no extra CSS attached) all sit in their parent's formatting context.

Only when a block has properties like position, float, opacity etc., does a new formatting context get created for the block and its contents.

And to answer your question what's it called when a block does not create a BFC of its own, that's simply what the W3C page calls "normal flow".

Implications of Block Formatting Context

A block formatting context is a tool to help browsers render elements. It prevents tricky cases, so it's not really visual.

For example, float elements are not in the page flow. So other elements could be under or wrap around a floating element.

.float {  float: left;  width: 50px;  height: 50px;  margin: 10px;  background: turquoise;}
.container { height: 100px; margin-left: 30px; background: tomato;}
<div class="float"></div><div class="container"></div>

How can block container establish both block and inline formatting contexts at the same time?

It's entirely possible, and even necessary for certain CSS rules. The easiest way to understand this is with an example of such a box.

<div style="overflow:auto">hello world</div>

Here we have an element with display:block (by default for div elements) and overflow:auto. This is one way that an element's rendered box will establish a block formatting context. This affects, for example, how the box's location and dimensions are affected by the presence of floats.

Compare these two examples:

.formatting.contexts {  overflow:visible;}
.container { width:70px;}
img { float:left; margin-right:3px;}
<div class="container">  <img src="http://placehold.it/16" alt="placeholder grey square less than one line in height">  <div class="formatting contexts">hello world</div></div>

What is meant by participate in the definition of “normal flow” in the CSS 2.1 spec?

When a box is said to participate in some formatting context, it just means that element is laid out according to the rules of that formatting context. If an element participates in a block formatting context, it's block-level and it's governed by block layout. If an element participates in an inline formatting context, it's inline-level and it's governed by inline layout. And so on.

"Block container box" and "block formatting context" are two different and only very loosely related concepts. You seem to be conflating them, which is unwise.

A block container box establishes a block formatting context only under certain conditions. The criteria for this to happen are listed in the spec, but basically the only time a block container box doesn't establish a BFC is when it has display: block; overflow: visible; float: none; position: static/relative (from here).

As stated in the spec, every block-level box participates in some block formatting context. It doesn't matter whether its parent block container establishes a BFC. If its parent doesn't establish a BFC, then the parent's parent, or the parent's parent's parent, or some other ancestor higher up in the tree — all the way up to the root element — does. This means that a single block formatting context can — and almost always does — encompass many nesting levels of elements. This is collectively referred to as the normal flow.

Even if you had an entire layout of block boxes, if none of them establishes a BFC, then all of them participate in the same BFC that's established by the root element (and the root element is guaranteed to establish one). In the following example, all three elements participate in the root element's BFC, and so they are governed by block layout, even though none of them establishes its own BFC:

<body>
<div>
<p>
</div>
</body>

The effects of overflow: hidden on block formatting contexts in the presence of floats are discussed elsewhere, but in short, floats never intrude into other block formatting contexts, which is why making the p establish its own BFC causes it to become narrower due to the float. Making the div establish its own BFC doesn't change anything because, once again, the p is still participating in some BFC regardless — you're just changing whose BFC it's participating in.

Block Level Element vs Block Formatting Context

Note that this answer uses the term "box" in lieu of "element", as CSS makes a distinction between elements and boxes. For the purposes of this answer, an HTML element is represented by a single box in CSS layout. In reality an element may generate any number of boxes (or none at all, as in display: none), but that's outside the scope of this question.

Can a HTML element be both a block level element and form a block formatting context?

Yes. The criteria in which a block box (i.e. a block-level block container box) may establish a BFC are stated in section 9.4.1 of CSS2.1, namely:

  • floats,
  • absolutely positioned elements, and
  • "block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport)" (as directly quoted from the spec)

Does being a block level element imply that it forms a block formatting context, or conversely, does forming a block formatting context imply that it must be a block level element?

Neither:

  1. The above answer implies that not all block boxes establish block formatting contexts. A block box with the CSS properties display: block; overflow: visible; float: none; position: static (or position: relative) does not establish a BFC.
  2. Conversely, an inline-block is an example of a box that establishes a BFC, but is itself inline-level, not block-level.

In a similar vein, how does this translate to inline elements and elements that form an inline formatting context?

An inline box is an inline-level box whose contents participate directly in its parent's inline formatting context (see section 9.4.2). Notably, the only boxes that can establish inline formatting contexts are block container boxes.

The difference between an inline box and an inline-block is that an inline-block's contents participate in the BFC that it establishes, not in the parent's IFC. Instead, only the inline-block itself participates in its parent's IFC.



Related Topics



Leave a reply



Submit