Repository navigation
[css-display] Unclear definition of "formatting context" #5105
Description
I find the definition of formatting context in the spec a bit unclear.
A formatting context is the environment into which a set of related boxes are laid out.
What is an "environment"? This is one of those typical blanket words. Without giving a definition of environment, this sentence is not saying much. I'll take for now FC as synonym with "box layout", where layout is a visual arrangement.
A box either establishes a new independent formatting context or continues the formatting context of its containing block.
So each box establishes a formatting context (defines a layout) for its descendant boxes. This makes sense, since its descendant subtree must be laid out somehow. But what does "continue a formatting context" mean here? How can one box nested inside another can continue in the identical layout the other is in? After all the nested box is visually "inside" the other box. Does "continue" rather mean the box establishes a new formatting context of the same type as the one of its containing block?
Also I'm not sure if "containing block" is correct here. It's defined in the specific layout "Positioned Layout" which is one type of layout of many (Flow / Block-Inline, Grid, Flex, Table), so using it as part of the definition of layouts in general is kind of circular.
The type of formatting context established by the box is determined by its inner display type
An inner display type is defined for an element, not for a box. The inner display type may even generate multiple boxes with each different formatting contexts, like for display: table.
As an aside, there are more definitions that are circular, like for example of "inline box"
A non-replaced inline-level box [box that participates in inline formatting context] whose inner display type is
flow.
Ok, same problem to above, a box doesn't have a display type, the associated element does. But let's read on what inner display type flow does.
If its outer display type is inline [..], and it is participating in a block or inline formatting context, then it generates an inline box.
Ugh. Am I the only one that has a hard time making sense of the current spec?
Activity
faceless2 commentedon May 22, 2020
Fragmentation. When a node is split into mulltiple boxes at the end of a line, page, column or region.
"Containing block" is a term that originates from CSS2 - a spec which is still useful to give a high-level overview of the process (something which, inevitably, has been a bit lost with the modularization of CSS3)
It's defined for both. But CSS layout primarily concerns itself with boxes.
I'm not sure what point you're trying to get at with all this - some of the definitions are a bit complicated, but CSS layout is complicated. If you're suggesting improvements to the wording, great, although I'm not clear what they are. And if you're trying to pick up the CSS display or box modules and expect to read it and fully understand what's going on, it's not going to happen. I think CSS2.1 is still a better resource for this - primarily because it has a start, middle and end rather than a collection of modules.
vwkd commentedon May 23, 2020
Thanks, I'll read more into fragmentation.
You're right, it is far from being easy to comprehend. Although from the parts of CSS2 I read while studying CSS layout I found CSS3 to be quite a bit clearer.
I think to clearly define all terms would help a great deal to improve clarity. The Glossary in css-display-3 is a first attempt at this, although it's still kind of a copy-paste from the relevant CSS2 sections and contains all of these circular definitions.
I'd be happy to improve the wording myself if I understood the whole thing but I don't. Until then, the point of my post can be seen as a readers feedback.
Loirooriol commentedon May 23, 2020
For example, subgrids
Then
#foois a grid container and establishes a grid formatting context (GFC).#baris a grid item, it participates in that GFC. And#baris also a grid container, but does not establish an independent GFC. Instead,#baz, a subgrid item of#bar, participates in the GFC established by#foo.Another example: nested inlines.
Then
#foois a block container and establishes an inline formatting context (IFC).#baris an inline which participates in that IFC.#bardoes not establish any FC of its own, so#bazparticipates in the IFC established by#foo.Another example: nested blocks.
Then
#foois a block container and establishes a block formatting context (BFC).#baris a block which participates in that BFC.#bardoes not establish any FC of its own, so#bazparticipates in the BFC established by#foo.I disagree with "fragmentation". Fragmentation is relevant to the fragment tree, here we are talking about the box tree.
Seems correct. It can't be "parent box" because you can have a block inside an inline. The inline is participating in an inline formatting context (IFC), but the block is participating in a block formatting context (BFC). And the IFC may be established by a descendant of the BFC root.
Well, technically the containing block is just a rectangle, but there is handwaving: "If properties of a containing block are referenced, they reference the values on the box that generated the containing block."
Oh, see #1480. The outcome was good enough for me, but you seem more purist :)
Note that the proper place for defining "inline box" is the Flow Layout spec, which doesn't exist yet. CSS Display is just trying to provide a quick summary.
faceless2 commentedon May 23, 2020
@Loirooriol ah yes sorry, you're right. It's not fragmentation, I misread the original text.
vwkd commentedon May 23, 2020
Thanks @Loirooriol, I really appreciate the examples.
To be able for me to understand any of it, it's logically necessary to first establish a solid definition of formatting context, as the given definition as "environment" is not clear. I'm kind of fishing in the dark, since without the proper definition, I can't understand it, and without understanding it, I can't come up with the proper definition. It's like finding the mathematical function that maps each input to the correct output given only the input-output pairs.
I've been trying out a few definitions and want to share my latest attempt. It's not fully watertight though as there are still places in the spec which it can't explain. Please correct me, wherever my reasoning is wrong.
where "box layout" is Flow Layout, Flex Layout, Grid Layout, Table Layout, etc. as defined in the different Layout modules.
A formatting context can be thought of as "way to arrange a given set of boxes". Mathematically it can be thought of as a function which takes a set of boxes and assigns them coordinates and sizes.
It needs to be defined how a formatting context treats nested boxes. Most certainly we want to keep the boxes in the same logical order as they are nested in the box tree. For example in an inline formatting context, we want the following to be laid out as
foo1 bar1 bazbaz kikkik bar2 foo2.How would the formatting context define this order? What makes "bazbaz" come before "bar2" or "foo2"?
To solve this, we let each box define a formatting context. An formatting context applies only to the immediate children. It deals only with the flat set of boxes of box tree depth
0and leaves any subtree that might be contained in it to the formatting contexts of the nested boxes.So the formatting context of
fooonly lays out "foo1",barand "foo2". Thenbarcreates a formatting context which lays out "bar1",baz,kikand "bar2". And so on recursively.The layout of boxes in a given formatting context is confined by the box that establishes the parent formatting context. Essentially, a given formatting context doesn't see the outside world. All it knows is the position constraint within the box of the parent formatting context.
The formatting contexts are nested in the same way as the box tree.
The advantage of this definition of the term "formatting context" is that it makes it compatible with the definitions of the different existing formatting context. For example, the block formatting context reads
Similarly, the inline formatting context says "horizontally" instead. There is no notion of nested boxes. By eliminating the need for the formatting context to know how to handle nested boxes, the term becomes well defined. For this it was necessary that each box creates a formatting context, and this formatting context applies only to its immediate children.
Also there is no notion of "continuing an existing" formatting context vs. "creating a new" formatting context anymore. Each box creates a formatting context, which might or might not be the same as the parent formatting context.
In the above example each
foo,bar,bazandkikcreate an inline formatting context. Sofoocreates a formatting context in which it contains first "foo1" thenbarthen "foo2". Thenbarcreates a new formatting context in which it contains first "bar1" thenbazandkikand then "bar2". Finallybazandkikeach create a new formatting context which contain "bazbaz" and "kikkik" respectively.Since each formatting context is confined to the parent formatting context, this explains why nested boxes are confined by boxes from further up in the box tree. In the example, "bazbaz" can never come after "bar2" or "foo2", because the formatting context created by
bazis confined to the one created bybarwhich is confined to the one created byfoo.Visually I like to think about the formatting contexts being nested in the same way as the boxes.
Loirooriol commentedon May 23, 2020
Yes. I would say that a formatting context are the rules that dictate how to lay out descendant boxes.
Yes, and that's why we can't have all boxes establish an independent formatting context.
Note that the float shrinks the line boxes of
#child. But#childis not a sibling of the float, it's inside#parent. So if#parentestablished an independent formatting context,#childcould not be affected by the float.vwkd commentedon May 29, 2020
Thanks @Loirooriol, I like your definition of a formatting context. I guess I'm not fully on the right track yet. May I ask a few more questions to better understand it? I added quotes from the relevant parts of the spec.
With "additional boxes" I mean the boxes an element may generate in addition to its principal box.
Are these additional boxes always nested in the principal box in the box tree? Or can they be a sibling to the principal box in the box tree?
Otherwise the principal box could be defined as the "outermost" box generated by the element in the box tree, since any additional boxes are nested within the principal box.
Assuming there are no out-of-flow boxes, i.e. no floating boxes and no positioned boxes, what is the difference between creating a new independent FC and "continuing" the parent FC? Is there an example where there is a difference?
If "continuing" a FC by a child box is possible, then it must be asked how a formatting context handles a nested set of boxes. The nested boxes must "stay inside" the parent boxes (assuming no overflow) instead of being laid out sequentially. But the current definitions of formatting context doesn't handle the case of nested boxes. For example
This problem was also what I tried to highlight in my previous answer.
How can two sets of "rules that dictate how to lay out descendant boxes" co-exist without destructively interfering? Can't these "co-existing" formatting contexts simply be interpreted as a single (new) formatting context, which is the union of the rules that make up the individual FCs? Like supersets so to speak?
For example, a block formatting context could be viewed as a superset of an inline FC. It allows block-level boxes to flow in block direction but also inline-level boxes to flow in inline direction by distributing them in block-level wrapper line boxes.
Loirooriol commentedon May 29, 2020
I think this is currently the case, yes.
Seems reasonable to me.
It means that the box doesn't establish an independent formatting context, so its children will participate in the parent formatting context.
Well, for example margin collapse only happens in the same BFC. See the difderences in
Well, that's because block and inline layout are two sides of the same coin (flow layout). So yes, you can consider flow layout to be a superset of block layout and inline layout.
Though I'm actually not pleased by this FC coexistence, I think that element-generated block containers should either continue their parent BFC or establish an independent BFC, but never an IFC. IFC should only be established by anonymous block containers IMO.
emilio commentedon May 29, 2020
I don't think that's true of the table wrapper box, nor the boxes that are created for blocks-inside-inlines, fwiw.
vwkd commentedon May 29, 2020
@Loirooriol Thanks again, these are great examples!
I also agree that a block container should strictly establish BFCs and not IFCs. The current definition is very confusing.
(note how the outer display type was not specified, meaning it can be either inline-level or block-level). Instead of filling in the "?" in the below table, it is a general term for either entry, basically a "flow container". Not really useful.
@emilio The first is still true, since the table wrapper box is the principal box and not the table grid box.
Regarding the second, I don't understand what you mean. Do you mean line boxes?
Loirooriol commentedon May 29, 2020
@emilio Why not? The principal box is the table wrapper box, which contains the table grid box.
For blocks-inside-inlines, see the resolution in #1477 (comment): the behavior is sane in the box tree and the block box stays inside the inline box, which is not split (so there is a single inline box, the principal one). All the splitting mess is confined into the fragment tree.
emilio commentedon May 29, 2020
Ah, that's true, though it's a bit unintuitive IMO (I prefer to think of the wrapper box as an anonymous box, as only a handful of styles in the grid box apply to the table box).
Re #1477, sure, but that's not how any implementation works, as far as I can tell :)
tabatkins commentedon Aug 5, 2021
Closing as “no change”; as far as we can tell, while it is not a precise mathematical definition, everything is defined precisely enough as English to support the definition of CSS layout. We could redefine things in a more strict algorithmic style, but it doesn't seem like doing so would solve any problems in practice, and it would make the text much more complex to read, particularly in light of the way various boxes and their descendants interact in, e.g., block and inline formatting contexts, and cannot be simplified to basic parent-child relationships.
Although block, inline, and ruby formatting contexts do need further definition, that job is for the Inline, Ruby, and Block Layout specifications, not Display (noting that the Block Layout specification does not yet exist, except insofar as CSS2 covers it).
We think the current text of Display, while it might not be ideal, is sufficient for its purpose, which is to clarify that all these layout models intermesh in a complex way, rather than being isolated by an FC boundary like most other layout modes are.
~@tabatkins and @fantasai