CSSContaining Blocks

containing blocks

A containing block is the reference rectangle that an element is positioned and sized relative to. For most elements, the containing block is the parent's content box. For absolutely positioned elements, it's the nearest positioned ancestor's padding box. For fixed elements, it's the viewport. Understanding containing blocks is crucial for accurate positioning, percentage-based sizing, and debugging layout bugs.

What is a containing block?

Every element in the CSS box model has a containing block. The containing block provides a reference frame for:

  • Positioning: top, right, bottom, left values are relative to the containing block
  • Sizing: Percentage widths and heights are relative to the containing block's dimensions
  • Layout: Child elements flow within the containing block's space

CSS
<!-- Simple containing block relationship -->
<div class="parent">
  <div class="child">I'm positioned relative to parent</div>
</div>

.parent {
  width: 300px;
  height: 200px;
}

.child {
  width: 50%;        /* 50% of parent width = 150px */
  height: 50%;       /* 50% of parent height = 100px */
  /* parent is the containing block */
}

.child {
  position: relative;
  top: 20px;
  left: 20px;
  /* Positioned relative to parent (containing block) */
}
Determining the containing block

Element type

Containing block

Reference

Normal flow (static)

Parent's content box

Block parent or inline parent

Relative positioned

Parent's content box

Same as static

Absolutely positioned

Nearest positioned ancestor

position is not static

Fixed positioned

Viewport (or document in some cases)

Browser window

Inline elements

Parent inline box

Generated by inline parent

For static and relative positioned elements

CSS
<!-- Parent is the containing block -->
<div class="parent">
  <div class="child">Static or relative</div>
</div>

.parent {
  width: 400px;
  height: 300px;
}

.child {
  width: 50%;  /* 50% of 400px = 200px */
  /* Parent's content box is containing block */
}

<!-- Nested parents -->
<div class="grandparent">
  <div class="parent">
    <div class="child">Percentage sizing</div>
  </div>
</div>

.grandparent { width: 600px; }
.parent { width: 400px; }

.child {
  width: 50%;  /* 50% of parent (400px) = 200px */
  /* parent is containing block, NOT grandparent */
}
For absolutely positioned elements

This is where containing blocks get tricky. For absolutely positioned elements, the containing block is the nearest ancestor with a position value other than static.

CSS
<!-- With positioned parent -->
<div class="parent">
  <div class="child">Absolutely positioned</div>
</div>

.parent {
  position: relative;  /* creates containing block */
  width: 300px;
  height: 200px;
}

.child {
  position: absolute;
  width: 50%;        /* 50% of parent = 150px */
  top: 20px;         /* 20px from parent top */
  left: 20px;        /* 20px from parent left */
}

<!-- Without positioned parent (containing block is viewport) -->
<div class="static-parent">
  <div class="child">Absolutely positioned</div>
</div>

.static-parent {
  /* position: static (default) */
  /* NOT a containing block */
}

.child {
  position: absolute;
  width: 50%;        /* 50% of VIEWPORT */
  top: 20px;         /* 20px from viewport top */
  left: 20px;        /* 20px from viewport left */
}
Creating a containing block

Several CSS properties create a containing block for absolutely positioned descendants. These include position: relative, position: absolute, position: fixed, and others.

CSS
<!-- These create containing blocks -->

/* position: relative */
.parent {
  position: relative;
}

/* position: absolute */
.parent {
  position: absolute;
}

/* position: fixed */
.parent {
  position: fixed;
}

/* position: sticky */
.parent {
  position: sticky;
}

/* transform (any non-identity value) */
.parent {
  transform: rotate(10deg);
}

/* opacity < 1 */
.parent {
  opacity: 0.5;
}

/* filter (any value) */
.parent {
  filter: blur(5px);
}

/* mix-blend-mode (any non-normal value) */
.parent {
  mix-blend-mode: multiply;
}

/* will-change (any value) */
.parent {
  will-change: transform;
}

<!-- Best practice: use position: relative for clarity -->
.parent {
  position: relative;  /* explicitly creates containing block */
}

.positioned-child {
  position: absolute;
  /* Clearly relates to parent */
}
Percentage sizing with containing blocks

CSS
<!-- Percentage width/height are relative to containing block -->
<div class="container">
  <div class="box">Percentage sized</div>
</div>

.container {
  width: 500px;
  height: 400px;
}

.box {
  width: 50%;    /* 50% of 500px = 250px */
  height: 50%;   /* 50% of 400px = 200px */
  /* container is containing block */
}

<!-- Percentage with auto width -->
.container {
  width: auto;   /* width determined by content */
  height: 400px;
}

.box {
  width: 50%;    /* 50% of... what? Container has auto width */
  /* Percentage width doesn't work well with auto parent */
}

<!-- Solution: explicit parent width -->
.container {
  width: 100%;   /* explicit width */
  height: 400px;
}

.box {
  width: 50%;    /* now works: 50% of 100% = 50% */
}
Containing block for different properties

Property

Relative to containing block

width, height

Yes (percentage values)

padding, margin

Yes (percentage values)

top, right, bottom, left

Yes (for positioned elements)

background-position

Yes (position coordinates)

transform

No (relative to element's own box)

translate()

No (relative to element's own box)

Common containing block problems and solutions

CSS
<!-- Problem: percentage width doesn't work -->
<div class="parent">
  <div class="child">Child</div>
</div>

.parent {
  /* width: auto (default, based on children) */
}

.child {
  width: 50%;  /* doesn't work as expected */
}

<!-- Solution: give parent explicit width -->
.parent {
  width: 100%;  /* explicit width */
}

.child {
  width: 50%;  /* now works */
}

<!-- Problem: absolute positioning goes to viewport -->
<div class="static-parent">
  <div class="child">Positioned</div>
</div>

.static-parent {
  /* position: static (not a containing block) */
}

.child {
  position: absolute;
  top: 0;
  left: 0;  /* positioned to viewport, not parent */
}

<!-- Solution: add position: relative to parent -->
.static-parent {
  position: relative;  /* creates containing block */
}

.child {
  position: absolute;
  top: 0;
  left: 0;  /* now positioned relative to parent */
}

<!-- Problem: fixed element inside transform -->
.parent {
  transform: rotate(10deg);  /* creates containing block */
}

.fixed-child {
  position: fixed;
  top: 0;
  left: 0;  /* positioned to parent, not viewport! */
}

<!-- Solution: don't use transform on parent with fixed children -->
<!-- or remove transform temporarily for specific fixed elements -->
Note
The most important rule for positioning: to control where an absolutely positioned element goes, set `position: relative` on the parent. This makes the parent the containing block.
Transforms create containing blocks unexpectedly
Many CSS properties create containing blocks as a side effect: `transform`, `opacity < 1`, `filter`, etc. If your fixed or absolute positioning is unexpectedly constrained, check if a parent has one of these properties applied.
Section complete
Congratulations! You've now covered all the fundamentals of CSS layout. From display properties through positioning, floats, overflow, and containing blocks, you have a solid foundation for creating any layout. The next major sections cover advanced layout systems: flexbox and grid.