Engrain by ByteRush

WEB.09.02 Mid-level· 10 minCore — asked often

Positioning and containing blocks: why your fixed header moved

Which box each position value is placed against, why transform, filter and contain on an ancestor trap position: fixed, what sticky needs to work, and the inset shorthand.

Comes up in: Web fundamentals, UI coding

Learn#

Priya’s fixed header scrolls away on one page only. Nothing changed in the header’s CSS. A wrapper three levels up got a transform for a slide-in animation.

Every positioned box is placed against a containing block. That is the box that top, left and percentages refer to. The table shows which box that is for each position value.

positionContaining block
static, relative, stickyThe nearest block container ancestor (usually the parent)
absoluteThe nearest ancestor that is positioned (not static), or the initial containing block
fixedThe viewport, unless an ancestor has transform, filter, perspective or containment

That last exception is Priya’s bug. A transform on any ancestor makes it the containing block for fixed children. So “fixed” now means “fixed to that ancestor”.

A transform traps a fixed headerStep 1 of 4

State

  • header → containing block: viewport

Page

    empty

    The header has position: fixed and top: 0. Normally its containing block is the viewport, so it stays put while scrolling.

    Read the steps as text
    1. The header has position: fixed and top: 0. Normally its containing block is the viewport, so it stays put while scrolling.
    2. A teammate adds a slide-in animation to the page wrapper: transform: translateX(0).
    3. Any transform on an ancestor makes that ancestor the containing block for fixed descendants.
    4. Now the header scrolls away with the page. Removing the transform, or moving the header outside the wrapper, fixes it.

    Predict#

    Predict first

    A sidebar has position: sticky; top: 0, but it never sticks. Its parent has overflow: hidden. Why?

    Interview angle#

    Say it like this — about 30 seconds

    “Every positioned element is laid out against a containing block. For absolute, it is the nearest positioned ancestor. For fixed, it is normally the viewport. But a transform, filter or containment on an ancestor makes that ancestor the containing block. That is a classic broken-header bug. Sticky needs a threshold such as top: 0. It sticks within its nearest scrolling ancestor, and only while its parent is on screen. So an overflow hidden or a short parent stops it.”

    Stays on your device. Nothing is uploaded.
    Follow-up What does position: sticky need to work?
    An offset (top, bottom, left or right), room to move inside its parent, and no ancestor between it and the real scroller with overflow other than visible.
    Follow-up Why is my fixed header broken inside a transformed parent?
    Transform makes the ancestor the containing block for fixed descendants; move the header out, or remove the transform.
    Follow-up What does inset: 0 mean?
    Shorthand for top, right, bottom and left all set to 0: it stretches an absolute element over its containing block.

    Practice#

    Guided

    Encode the containing-block rules, including the traps that capture fixed elements.

    Done when

    • Absolute finds the nearest positioned ancestor or trap, else “initial”.
    • Fixed finds the nearest trap, else “viewport”.
    • Static, relative and sticky return the parent.
    Your solution
    Ctrl/⌘ + Enter

    Remember#

    Try to answer each card before you open it. Then add them to your reviews.

    What is the containing block of an absolute element?

    Its nearest positioned ancestor (or the initial containing block).

    Name three ancestor properties that trap position: fixed.

    transform, filter, perspective (also contain and will-change).

    What does sticky need?

    An offset such as top: 0 and a scrolling ancestor it can stick within.

    What does inset: 0 set?

    top, right, bottom and left to 0.

    Go deeper

    Four layers. Stop at the one your interview needs; each ends with a quick check.

    The core ideaEvery round

    Percentages in top, left, width and height refer to the containing block. For absolute elements, it is the inside edge of the positioned ancestor’s border Source: MDN: Layout and the containing block.

    Check yourself: What does top: 50% of an absolute element refer to?

    50% of its containing block's height.

    How it works underneathSenior rounds

    will-change: transform creates a containing block even before any transform runs, because the browser prepares for one. contain: paint and layout do too Source: CSS Transforms 1: containing block for all descendants.

    Check yourself: Does will-change: transform trap fixed descendants?

    Yes, it behaves as if a transform were set.

    Edge cases and trapsWhere people slip
    Sticky positioning acts like relative until the threshold is reached, then like fixed within the scroller, but it never leaves its parent. A parent no taller than the sticky element leaves no room to stick.
    Check yourself: Why does a sticky element stop sticking near the end of its section?

    It cannot leave its parent; it stops at the parent's edge.

    In productionStaff-level answers

    inset sets all four offsets at once, as in inset: 0 for overlays.
    Render fixed headers and toasts near the root (React portals), or use <dialog> and popovers, which live in the top layer (WEB.07.02).

    Check yourself: Where should a fixed header or modal live in the DOM to avoid traps?

    Near the root, outside animated wrappers, or in the top layer.

    Finished the five steps? Mark it, and its cards join your reviews.

    Last checked 2026-11-01. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

    Interview questions this answers

    • What does position: sticky need to work?