How Can Block Container Establish Both Block and Inline Formatting Contexts at the Same Time

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>

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".

What is the difference between 'containing block' and 'block container box' in CSS?

Let's start at the beginning. CSS is almost entirely about boxes. A box is just a rectangular area of the canvas. The canvas is the entire 2D space on which everything is drawn.

CSS Boxes have a whole range of flavours. Block boxes, block-level boxes, inline boxes, inline-level boxes, content boxes, padding boxes, border boxes, margin boxes, table boxes, line boxes, flex boxes, and so on. They're all just rectangular areas.

So a block is just one type of box. Many of the above boxes are characterized by two behaviours - how they are laid out relative to their containers and peers, and how their content is laid out within them. The CSS-display spec refers to these as display-outside and display-inside respectively

Display-outside refers to the "*-level" nature of the boxes. They're not what we're interested in here.

All block boxes, and some inline-level boxes are block container boxes. A block container box is a box of type "block container", not necessarily a box that contains blocks. Block containers that are not block-level boxes include those that are display:inline-block and display:table-cell

The "block" in "block container" refers to its display-inside behaviour. Block boxes are laid out vertically within them and text flows horizontally, ordinarily limited by its edges of the rectangle.

So a "block container box" is a type of box. In contrast, "containing block" refers to a specific box. Each box defined on the canvas has exactly one containing block, with just one exception, called the initial containing block, which has no containing block.

Only a box of type "block container box" can be a box's containing block.

Time for an example. Let's suppose we have the HTML below: I'm deliberately going to use <span> elements throughout, because this is all about CSS, and I don't want to confuse with HTML behaviour.

<span id="level1">
foo
<span id="level2">
bar
<span id="level3">
baz
<span id="level4">
qux
</span>
</span>
</span>
</span>

The CSS is very simple. Just

#level1 { display:inline-block }

The other spans are the CSS default display setting, "inline".

Now, consider the #level4 span. Its parent is the '#level3' span, which is display:inline so the '#level3' span does not form a block container box. Similarly, the #level2 span also does not form a block container box. But the #level1 element is display:inline-block. That forms an inline-level box, but one that is a block container box. (This is what "inline-block" means).

So the containing block for all the inline boxes formed by the #level2, #level3, #level4 spans and their text content is the block container box formed by the #level1 element's box.

Do Inline elements establish a Line Box for their content?

Your heading and first paragraph ask two different questions:

  • Do Inline elements establish a Line Box for their content?
  • [Are] line boxes are formed inside inline-level elements?

They have different answers, "No", and "Sometimes" respectively, so the first thing that needs to be dealt with is the -level suffix.

An inline-level box is a broader category than an inline box. A span element which contains only text generates, by default, a sequence of inline boxes sufficient to lay out that text content over as many lines as is necessary. All inline boxes are also inline-level boxes, but the opposite is not true. Elements whose computed display is inline-block, inline-table, inline-flex and inline-grid all generate boxes that are inline-level, but are not inline boxes.

Similar applies to block versus block-level. Block-level describes how a box lays out relative to its parents and siblings. Block containers are boxes in which their child boxes are laid out either as sequence of block-level boxes, or within a stack of line boxes, and never as a mixture of both.

Elements whose computed display value is block, flow-root and list-item and are being laid out in a block formatting context (i.e. they're not a flex item or a grid item) generate a single box that is both block-level and a block container. These are called block boxes.

But boxes generated for elements that have computed display values of table, flex, and grid are block-level, but they are not block containers. Their descendants are laid out using different rules. These are not block boxes.

Conversely, elements that have computed display values of inline-block and table-cell generate boxes that are block containers but they are not block-level. They interact with their parents and siblings differently than block level boxes do.

So, specifically, inline-block boxes, which are inline-level, contain either a sequence of block-level boxes, or a stack of line boxes in which other inline-level boxes are laid out.


Now, an inline box can contain other inline-level boxes, but that does not make it a block container, even if one of those inline-level boxes is itself a block container. The block container of the inline box and all its descendant inline-level boxes that are not themselves inside other formatting contexts is the nearest ancestor that is a block container.

So, suppose we have this tree of boxes

 display:block                     block level, block container
| ↑ ↑
+ - display:inline inline level ---------+ | \
| | |- In the same line box
+ - display:inline-block inline level, block container /
| ↑
+ some text anonymous inline box --+ in a line box

where the arrows point from inline-level boxes to their block container.

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.

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>


Related Topics



Leave a reply



Submit