In CSS, what is a block formatting context, and which declarations establish a new one?
answer
- a sealed region of block layout
- nothing crosses the boundary
- overflow, floats, absolute, inline-block, table-cell
- flex and grid items get their own
- flow-root asks for it directly
basics
~20 sA block formatting context is a self-contained region of block layout: floats inside it are contained, outside floats cannot intrude, and margins cannot collapse through its boundary. overflow other than visible, display: flow-root, floats, absolutely positioned boxes, inline-blocks, table cells and flex or grid items each establish one.
solid answer
~50 sA block formatting context is the region in which block-level boxes are laid out, and a **new** one is an isolated region: the boxes inside it lay out against each other and nothing crosses the boundary. Concretely, three things follow. The context contains its floated descendants, so its height includes them; margins inside cannot collapse with margins outside; and its box will not overlap a float that lives outside it, which is what makes a sidebar-plus-content layout hold together. It is established by the root element, by any box with `float` other than `none`, by `position: absolute` or `fixed`, by `display: inline-block`, `table-cell`, `table-caption` or `flow-root`, by a block container with `overflow` other than `visible` or `clip`, by a multi-column container, by `contain: layout`, `content` or `paint`, and by every flex and grid item. `display: flow-root` is the one that exists purely for this — it isolates the layout and does nothing else, unlike `overflow: hidden`, which also clips and creates a scroll container.
code
css · 12 lines.isolated {
display: flow-root;
}
.also-isolated {
overflow: auto;
}
.not-isolated {
position: relative;
z-index: 1;
}go deeper
Be able to say that some declarations create a self-contained layout region, and name the common ones — overflow: hidden, display: flow-root, inline-block, floats. Do not worry about the full list.
Explain the three consequences of a new context — floats contained, margins unable to collapse through, and the box not overlapping outside floats — and be able to recite the main establishers accurately.
Show the judgment: pick display: flow-root over overflow: hidden and explain what the latter costs in clipping, scroll containers and sticky behaviour. Be precise about flex and grid containers versus items.
Own the codebase-wide angle: legacy stylesheets are full of overflow: hidden used purely for layout isolation, and each one is a latent clipping bug. Decide how to sweep them, and set the convention that isolation is declared, not obtained as a side effect.
## Formatting context: the word means "a region with its own rules" A **formatting context** is an area of the page in which a particular layout algorithm runs. Block-level boxes in normal flow are laid out in a *block formatting context* (BFC): stacked one after another down the block axis, each one starting at the containing block's start edge, with adjoining vertical margins collapsing. Inline-level content lays out in an *inline formatting context*, flex containers run a flex formatting context for their children, grid containers a grid formatting context. The interesting question is not what a BFC is but what a **new** one does, because a new BFC is an *independent* one: layout inside it is sealed off from layout outside it. ## What isolation actually buys you Three observable consequences, and they are the reason anyone learns this at all: 1. **Floated descendants are contained.** A BFC's height calculation includes its floated children, so a container full of floats no longer collapses to zero height. 2. **Margins cannot collapse across the boundary.** A child's vertical margin cannot join with the parent's or escape the container, because collapsing only happens between boxes in the same BFC. 3. **The box does not overlap outside floats.** A normal block box slides *under* an earlier float and only its line boxes are shortened; a box that establishes a BFC is instead placed beside the float. This is what makes the classic "float the sidebar, give the content its own BFC" layout produce two real columns instead of text wrapping around a block. ## The list of establishers A new block formatting context is established by: - the **root element** (`<html>`), which sits in the initial containing block; - any box with **`float`** other than `none`; - **absolutely positioned** boxes — `position: absolute` and `position: fixed`; - **`display: inline-block`**, and `display: table-cell` / `table-caption` (plus the anonymous boxes tables generate); - a block container with **`overflow`** other than `visible` or `clip` — so `hidden`, `auto` and `scroll`, with the caveat that the value does nothing here if it has been propagated to the viewport, as happens with `overflow` on `<html>` or `<body>`; - **`display: flow-root`**; - **multi-column containers**, meaning `column-count` or `column-width` other than `auto`, and boxes with `column-span: all`; - **`contain: layout`**, `contain: content`, `contain: paint` and `contain: strict`; - **flex items and grid items** — a child of a flex or grid container establishes an independent formatting context of its own. Specs usually phrase the newer entries as "establishes an independent formatting context", a slightly broader term that also covers non-block inner layouts; for a block container it means precisely a new BFC. ## The nuance interviewers push on: containers versus items `display: flex` on an element does not give that element a block formatting context for its children — it gives them a **flex** formatting context. What it does do is make the flex container an independent formatting context with respect to the *outside*: outside floats cannot intrude into it and its margins do not collapse with its children's, since flex containers never collapse margins with their contents. And each **item** inside establishes its own independent formatting context, which is why a stray margin on a flex item's child never escapes. ## Why display: flow-root exists Every pre-2018 way to get a BFC was a side effect of asking for something else. `overflow: hidden` clips descendants, which quietly destroys tooltips, dropdowns and focus rings that need to escape, and makes the element a scroll container — which changes `position: sticky` behaviour, scroll anchoring and programmatic scrolling. `float: left` takes the box out of flow. `display: inline-block` makes the box shrink-to-fit and baseline-aligned. `position: absolute` removes it from flow entirely. `display: flow-root` is the honest declaration: outer display type `block`, inner display type `flow-root`, meaning "lay my children out in flow, in a formatting context that is mine". Nothing is clipped, nothing scrolls, nothing leaves normal flow. It is supported in all modern browsers, and in new code it should be the default answer whenever what you actually want is layout isolation. ```css /* asks for layout isolation, gets clipping and a scroll container too */ .container { overflow: hidden; } /* asks for exactly layout isolation */ .container { display: flow-root; } ``` ## What does not create one `position: relative` does not. Neither does `display: block` on its own, nor `z-index`, `opacity`, `transform` or `filter` — those last few create a **stacking context**, which governs paint order rather than layout, and confusing the two is the single most common error on this question. A box can have one, both, or neither.
- Does display: flex on a container establish a block formatting context?Not for its children — they get a flex formatting context, not a block one. But the flex container is still an independent formatting context relative to the outside: outside floats cannot intrude, and it never collapses margins with its contents. Each flex item also establishes its own independent formatting context.
- What is the difference between a block formatting context and a stacking context?A BFC is a layout concept: it decides where boxes go, what contains floats, and where margins may collapse. A stacking context is a paint concept: it decides the order in which boxes are drawn and scopes `z-index` values. They have different triggers — `opacity` or `transform` create a stacking context but no BFC — and a box can have either, both or neither.
- Why did overflow: hidden become the popular way to get one, and what does it cost?It predates `display: flow-root` by well over a decade and was the shortest declaration that worked. It costs you clipping — any descendant that must visually escape, such as a dropdown, tooltip or focus ring, is cut off — and it makes the box a scroll container, which changes `position: sticky` containment, scroll anchoring and scroll-into-view behaviour. `display: flow-root` has none of that.
saying these in an interview costs you the question
- Says position: relative establishes a block formatting context
- Confuses a block formatting context with a stacking context
- Believes overflow: hidden is the only way to create one
- Claims a BFC changes z-index or paint order
- Thinks display: flex gives its children a block formatting context