Block Formatting Context: The CSS Concept Nobody Explained Properly
Understand what BFC is, why your margins collapse, why the container can't see the float, and how display: flow-root fixes all of it.
Have you ever added overflow: hidden to a container and magically it started wrapping a float? Or seen child element margins "leaking" outside the parent? These seemingly random CSS behaviors have a name: Block Formatting Context (BFC).
And once you understand what a BFC is, those bugs stop being bugs and become predictable behavior.
What Is a BFC
A BFC is an independent formatting area in CSS. Inside a BFC:
- Block elements are laid out vertically, one below the other
- Float heights are considered by the container
- Vertical margins of children don't collapse with the parent
The key word is independent. A BFC doesn't interfere with the layout outside it, and the outside doesn't interfere with the BFC.
Mental model: think of a BFC as a glass aquarium. Whatever lives inside follows its own laws of physics. Water doesn't leak out, outside air doesn't disturb the fish. Margins, floats, and layout flow stay contained. Once this image clicks, BFC stops being abstract spec language.
How to Create a BFC
display: flow-root was created specifically for this purpose. The others create a BFC as a side effect.
Browser support in 2026: display: flow-root is effectively universal. Firefox shipped it in 53 (April 2017), Chrome in 58 (April 2017), and Safari in 13 (September 2019). That's six and a half years of stable support across every evergreen browser. Unless you're supporting IE11 (condolences), just use it.
Problem 1: Margin Collapse
Without a BFC, vertical margins of children collapse with the container's:
With a BFC:
Visualizing what actually happens:
BEFORE BFC (margin leaks out) AFTER BFC (margin stays in)
↕ 20px margin (leaking) ┌──────────────────────┐
┌──────────────────────┐ │ ↕ 20px margin │
│ ┌────────────────┐ │ │ ┌────────────────┐ │
│ │ child 1 │ │ │ │ child 1 │ │
│ └────────────────┘ │ │ └────────────────┘ │
│ ↕ 20px collapsed │ │ ↕ 20px (real) │
│ ┌────────────────┐ │ │ ┌────────────────┐ │
│ │ child 2 │ │ │ │ child 2 │ │
│ └────────────────┘ │ │ └────────────────┘ │
└──────────────────────┘ │ ↕ 20px margin │
↕ 20px margin (leaking) └──────────────────────┘
Problem 2: Float Wrapping
The classic scenario: you put a floated element inside a container, and the container collapses as if the float didn't exist.
Before flow-root, we used the famous clearfix hack with pseudo-elements. An entire generation of devs had this burned into muscle memory:
It worked, but nobody explained why. Spoiler: it was creating a BFC through a side door. display: flow-root is the front door.
Problem 3: Sidebar Layout
When you have a floated sidebar and the main content flows underneath it:
The BFC on .content makes it respect the float's space instead of wrapping around it.
Common Pitfalls
Confusing BFC with Stacking Context: BFC controls layout (block positioning). Stacking Context controls painting order (z-index). They're independent.
overflow: hidden clipping content: If you just want a BFC without clipping anything, use display: flow-root. overflow: hidden triggers a BFC as a side effect, but its primary effect (clipping overflow) can catch you off guard, especially with tooltips, dropdowns, or focus rings that need to escape the container.
Floats inside flex containers: Floats are ignored on flex items. If the parent is flex, float on a child does nothing.
Nested BFCs are independent: Each BFC has its own rules. A BFC inside another doesn't interfere with the parent. Aquariums inside aquariums, all the way down.
FAQ
Do flexbox and grid already create a BFC? Yes, in practice. Flex and grid containers establish a new formatting context for their children (technically a flex/grid formatting context, but it behaves like a BFC for margin collapse and float containment). That's why you rarely see margin collapse bugs in modern flex layouts.
Does BFC matter in SSR/RSC? No. BFC is a pure rendering concept resolved by the browser's layout engine, not on the server. SSR and React Server Components emit the same HTML/CSS either way. No hydration gotchas here.
Any performance impact?
Negligible. Creating a BFC doesn't add layout cost by itself. What can cost is reaching for overflow: hidden or position: absolute just to trigger a BFC when you didn't want their side effects. flow-root is the cheapest, most intentional option.
Does contain: layout replace BFC?
Not exactly. contain: layout is a stronger isolation hint for the browser's layout engine, useful for performance in large subtrees, and per the CSS Containment spec it does establish an independent formatting context (effectively a BFC). But its purpose is performance containment, not layout fixes. For pure BFC needs, flow-root is clearer intent. Note that contain: layout support is also solid in 2026 (Chrome 52+, Firefox 69+, Safari 18+), though it landed in Safari much later than flow-root.
How do I debug BFC in DevTools?
Chrome DevTools still doesn't ship a "BFC badge", but you can inspect the computed display value and check for flow-root, flex, grid, or a non-visible overflow. Firefox's layout inspector visualizes float containment directly. When in doubt: temporarily add outline: 2px solid red and watch where the box actually ends.
Key Takeaways
- BFC is an independent formatting area (the aquarium) that solves margin collapse and float wrapping
- Use
display: flow-rootto create a BFC without side effects - Before reaching for hacks like clearfix, ask yourself: "do I need to create a BFC here?"
- Understanding BFC turns "random" CSS bugs into predictable behavior