Blog homepage RSS feed Mastodon Bluesky About me
This blog uses a new RSS feed. Please update the old QuirksBlog feed you used to follow.
Archives (1) CSS (2) Conferences (3) Personal (2) Safari (1) Site (2) Thidrekssaga (1)
I found an example of how we web developers wield CSS as black magic and reinforce its image as a weird and impossible language. Also, I learned to explain block formatting contexts.
Today, let’s demystify block formatting contexts in two ways:
overflow or container-type or any other black magic. Instead, use the "semantically correct" display: flow-root.
Paragraph doesn't work!
In my previous post I placed the CSS Day teaser image at the top of my post, where the floating bar that I call "floater" has been since at least 2003. Narrowing the page made the image fall to the bottom of the floater. We’ve all encountered this; it’s annoying.
I did what I do best. I exuded a noise on the Socials that the uninitiated take for plaintive mooing but is in fact a powerful summoning spell. Three friendly spirits, Temami Afif, Miriam Suzanne, and David Baron, appeared out of thin air to enlighten me.
Temami told me to use container-type: inline-size. This solved the bug. The paragraph now took the existence of the floater into account when calculating its width. No more falling to the bottom.
Fixed. But how? Why?
But why? What sort of black magic was this? Some sort of obscure side effect of container queries that I’m not acquainted with? (My experience with container queries so far is rather limited and basic.)
Then I had an insight and replaced the container-type with overflow: auto. Yup, that still worked.
Clearly, in addition to creating a container, container-type also engages the ... thingy ... the whatsitcalled that also works with overflow: auto ... the ... the block formatting context (or BFC).
I tested this by replacing the overflow with display: flow-root. It still worked fine. So making the paragraph a BFC solves the issue. Better still, I now sort-of understood what was going on, where I had been bewildered when staring at container-type.
This led to demystification #1: if you want to make something a BFC, just do it. Use display:flow-root. Be "pedantic-semantic" about it. Don’t use any of the other declarations that establish a BFC as a side effect. The developers who inherit your code will thank you for it.
I understand why people use other declarations. While figuring out what was going on I intuitively reached for the overflow: auto I’ve been using for more than twenty years to keep floats in check.
But that was the wrong reaction.
I didn’t want the paragraph to scroll. I didn’t want it to become a queryable container, either. Thus overflow and container-type were semantically incorrect. They reek of black magic and reinforce the image of CSS as this weird language that is impossible to learn.
By this time I kind-of vibe-grokked why the paragraph should be a BFC, but didn’t yet understand the exact reasons. David Baron came to the rescue and handed me demystification #2.
A BFC is a block that’s ready to scroll. (Well, it’s more complicated, but this is a good first approximation for newbies.) Take a look at this example.
The floating span that pushes content, or entire blocks, to the side, depending on the configuration
Contents of the first paragraph that will move to make place for the floater in any case — but will the paragraph block itself move as well? Only if it’s a flow-root.
Contents of the second paragraph that may also make place for the floater, depending on the exact circumstances. The paragraphs have a background colour in order to make them easily trackable.
Are the two paragraphs with the light background colour, the ones that say they are not a block formatting context, ready to scroll? That is, what would happen if the paragraph itself would have a scrollbar?
span? Would it be slowly pulled inside the paragraph, pixel by pixel? And if it did, what would happen to the second paragraph?span, one line after the other as they scroll into reach?You know the answer, I know the answer. That’s not how it works. That’s what I mean when I say these elements are not ready to scroll.
Let’s give the first paragraph an overflow: auto. You know how it’ll react, and so do I, but you may not have thought of it as getting ready to scroll. I sure didn’t. Yet that’s exactly what happens. The floating span is retracted into the paragraph so that it can scroll without influencing anything outside itself.
The floating span that pushes content, or entire blocks, to the side, depending on the configuration
Contents of the first paragraph that will move to make place for the floater in any case — but will the paragraph block itself move as well? Only if it’s a flow-root.
Contents of the second paragraph that may also make place for the floater, depending on the exact circumstances. The paragraphs have a background colour in order to make them easily trackable.
The effect becomes even clearer when we just use display: flow-root. Now the paragraph stretches up to accommodate the floating span. That makes it ready to scroll.
The floating span that pushes content, or entire blocks, to the side, depending on the configuration
Contents of the first paragraph that will move to make place for the floater in any case — but will the paragraph block itself move as well? Only if it’s a flow-root.
Contents of the second paragraph that may also make place for the floater, depending on the exact circumstances. The paragraphs have a background colour in order to make them easily trackable.
It won’t actually scroll, but that doesn’t matter. There are plenty of declarations that establish a BFC without scrolling, such as overflow: hidden. It should just be possible to scroll it.
Finally, what about the second paragraph? If we make it a BFC, it also gets ready to scroll.
The floating span that pushes content, or entire blocks, to the side, depending on the configuration
Contents of the first paragraph that will move to make place for the floater in any case — but will the paragraph block itself move as well? Only if it’s a flow-root.
Contents of the second paragraph that may also make place for the floater, depending on the exact circumstances. The paragraphs have a background colour in order to make them easily trackable.
In this case, getting ready to scroll means making sure it’s not able to be influenced by the float. The only real option of doing that is to move the entire block out of the way of the float. So that’s what happens, and it was this aspect of BFCs that solved the problem I had at the start of this article.
You’ll have to be much more specific and explicit if you aim for completeness, but a quick-and-dirty "getting ready to scroll" should be enough to explain the core concept of BFCs.