CSS Spec: Block-Level Box, Block Container Box and Block Box

CSS Spec: block-level box, block container box and block box

Your interpretation is correct.

Here are some additional details:

  • The reason a table box is not a block container is because it establishes a table layout, not a block layout. Content goes into the cell elements rather than the table element, which is why it is the cell boxes that are block containers rather than the table box itself.

  • A replaced element doesn't contain any other content and therefore cannot be a block container.

  • The only difference between a block box and an inline-block is that the former is block-level while the latter is inline-level. Hence the display values display: block and display: inline-block respectively. As both are block containers, there is no difference in how their contents are formatted.

Note that replaced elements and table boxes can be either inline-level or block-level. Inline tables and inline replaced elements are simply excluded from the section you quote because that section only pertains to block-level boxes; you'll find references to them elsewhere in section 9, or in sections 10 and 17 respectively.

Also, even though a block container box can only either contain block-level boxes or inline-level boxes, you can still mix both in the same block container box; internally it simply segregates the block-level and inline-level boxes via anonymous block boxes.

Clarifying definition of block container and block box

HTML elements are not CSS boxes. Zero, one, or multiple boxes are generated for a single HTML element.

The primary concept you're missing is that of an anonymous box.

Suppose you have

<section>
<span>Foo</span>
<div>Bar</div>
Baz
</section>

where section and div are display:block and span is display:inline, just as they are by default.

Now "Bar" and "Baz" get wrapped in anonymous inline boxes, and the span generates an inline box.

Further, because the block box generated by the section element would contain both inline boxes and block boxes, the span and "Baz" inline boxes are wrapped in anonymous block boxes. So the final box tree looks like this.

Block Box             <= from `section` element
+--- Block Box <= anonymous block box
| +--- Inline Box <= from `span` element
+--- Block Box <= from `div` element
| +--- Inline Box <= anonymous inline box from "Bar"
+--- Block Box <= anonymous block box
+--- Inline Box <= anonymous inline box from "Baz"

As you can see from this, no block box contains both a block box and an inline box as direct children, which is what your quoted paragraph is saying.

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.

What's the difference between a block-level box and a principal block-level box?

A principal block-level box is the block-level box generated by a given element that's directly affected by style rules that apply to the element.

Most elements generate only one box. For these elements, they are essentially the same thing, since there are no other boxes involved.

However, an element can generate more than one box depending on its display type, such as a list item; when you declare styles for such an element, the styles are typically applied to the principal box and any additional boxes that are generated will be rendered accordingly.

For example, a list item has a marker box in addition to the principal box; if you specify list-style-position: outside, the list marker will be placed outside the boundaries of the principal box but the background and borders of the principal box won't be affected. Note that the marker box is still a descendant of the principal box, so inheritable properties such as color will apply to the marker (this is why color: red turns both the text and its bullet marker red).

Most other block-level elements, including display: block but excluding display: table (see section 17.4), will simply generate a principal block box for their content and nothing else, making them essentially just "block boxes", but only for those elements.

In other words, all principal block-level boxes are block-level boxes, but not all block-level boxes are principal, for example anonymous block boxes. Also, inline elements, including inline blocks, do not generate any principal boxes themselves, nor is there such a thing as a principal inline box.

What are block container boxes in the visual formatting model?

<p> is already a block level element, so it treats it as such. Everything else inside the <div> is also treated as a (single) block level element. The specification doesn't say that each individual element will be treated as an individual block level element. Only that it will treat everything inside as block-level elements.

Therefore in your example

  <em>Emphasized text</em>
<em>More emphasized text</em>
More regular text.

This is all treated as a single block level element with multiple in-line elements inside it. Which fits with the specification.

Note that you can control this behavior by explicitly doing this:

  <div>
<em>Emphasized text</em>
<em>More emphasized text</em>
More regular text.
</div>

Or for the result you expected you can do this:

  <div><em>Emphasized text</em></div>
<div><em>More emphasized text</em></div>
<div>More regular text.</div>

Are Block-Level Boxes Enclosed in Line Boxes?

I'm not actually sure if a block-level box can be said to be adjoining to a line box (or vice versa). However, in your example, there are in fact two line boxes — one that is generated by div.one when formatting its inline contents by establishing an inline formatting context, and another that is generated by the body element when formatting span.two (and its span.three child) — and the line box inside div.one can be said to be adjoining to the one containing span.two and span.three.

For the purposes of drawing inline boxes, it doesn't matter which block container is generating each line box that's adjoining to those containing those inline boxes. It doesn't even matter whether any of the block containers also establishes a block formatting context. That is why you see the inline box of span.three bleed into the line box inside div.one.

A block-level box cannot directly coexist with a line box, and by definition of "block-level" it cannot be enclosed in a line box either (to answer your title). In your example, the line box on which the spans are rendered resides in an anonymous block box that is then laid out as a sibling of the div. That anonymous block box establishes its own inline formatting context for the spans, just like the div does for its text.

Identifying Anonymous Block Boxes

Box Generation will treat any boxes inside this block container as a block-level boxes. And by doing so, any boxes that is not a block-level box will be internally/conceptually treated as an anonymous block boxes, which is basically a block-level box anyway.

No, it creates anonymous block boxes with inline formatting contexts, which enclose the inlines. The inlines (or whatever other boxes that aren't block-level boxes) do not change. They continue to participate in the same formatting contexts they normally would; this algorithm ensures those formatting contexts are established by anonymous block boxes, that in turn participate in the same block formatting context as the parent element.

The illustration is mostly correct, with the exception that the principal block-level box doesn't always establish a block formatting context. You may also be getting the terms "block formatting context", "block-level box", "block container box", and "block box" mixed up; see my answers to these questions for additional clarification:

  • CSS Spec: block-level box, block container box and block box
  • Block Level Element vs Block Formatting Context

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: