Hello! Welcome to the next lesson in our deep dive into CSS.
In our last session, we explored the intricacies of margin collapsing, a behavior that occurs within the normal document flow. We saw how understanding the underlying rules and the concept of a Block Formatting Context (BFC) can help manage vertical spacing predictably.
Today, we're going to take a significant step beyond the normal flow. You'll learn how to use the position property to place elements with much greater control, sometimes removing them from the document flow entirely. Your learning goal for this lesson is to distinguish between relative, absolute, fixed, and sticky positioning and their respective containing blocks.
Mastering this topic hinges on understanding a single, powerful concept: the containing block. This is the "under-the-hood" mechanic that dictates an element's size and position when you take it out of the normal flow. For someone with your background, thinking about positioning as a set of rules relative to a defined context will be a natural fit.
We'll cover:
- The definition of the containing block and why it's the key to understanding positioning.
- The behavior of
relative,absolute,fixed, andstickypositioning. - How each positioning type determines its containing block.
- The critical edge cases where the containing block can change unexpectedly.
The Foundation: What is a Containing Block?
Before we look at the different position values, we must first understand the concept that governs them. A containing block is the "box" that an element's size and position are calculated relative to. While it's often the content area of the nearest block-level parent, this is not always true. The position property is the primary factor that changes this rule.
To get the most precise, technical definition, let's start with the official documentation from MDN.
Layout and the containing block - CSS - MDN
The MDN Web Docs article 'Layout and the containing block' provides the definitive rules for how a containing block is identified. This is the core theory for this entire lesson.
Read the section titled 'Identifying the containing block'. Pay close attention to the rules for each position value. We will be referring back to these rules throughout the lesson.
As you just read, the rules are different for each position value. Let's break them down one by one, starting with the default.
position: static: This is the default value. The element exists in the normal document flow. As the MDN article states, its containing block is the content box of the nearest block container ancestor. Offset properties liketopandlefthave no effect.
position: relative
Relative positioning is the most subtle. An element with position: relative remains in the normal document flow, and the space it occupies is preserved. However, you can now use top, left, bottom, and right to offset it from its original position. Other elements on the page are not affected and will not reflow to fill the gap it leaves behind.
To see this in action, the 'CSS position deep dive' video by Kevin Powell has a great segment that clearly illustrates how position: relative works.
Watch from 02:54 to 04:30. Notice how the element is visually shifted, but the space it originally occupied remains empty, causing it to overlap other content.
Containing Block for relative: The rule is the same as for static. The containing block is the content box of the nearest block container.
The most common and powerful use of position: relative, however, isn't to move the element itself, but to serve as a containing block for absolutely positioned children. This is a fundamental pattern in CSS layout, which we'll see next.
position: absolute
This is where things get interesting. When you set position: absolute, the element is completely removed from the normal document flow. Other elements behave as if it isn't there. Its position is now dictated entirely by its containing block, using the offset properties (top, left, etc.).
So, what is its containing block?
As defined by the MDN article and demonstrated in the next video, the containing block for an absolutely positioned element becomes the padding box of the nearest ancestor that has a position value other than static.
This is why you so often see position: relative on a parent and position: absolute on a child. The position: relative on the parent does little on its own, but it establishes a containing block for its descendants.
Stop fighting with CSS positioning
Kevin Powell's video, 'Stop fighting with CSS positioning,' is built around this exact concept. It provides an excellent conceptual explanation of how absolute positioning relates to its new containing block.
Watch from 03:51 to 12:04. This is a critical section. Focus on: What happens when an element is set to position: absolute without a positioned ancestor (it's positioned relative to the initial containing block). How adding position: relative to an ancestor 'traps' the absolutely positioned element. The crucial detail that the containing block becomes the ancestor's padding box, not its content box.
If no positioned ancestor is found, the containing block defaults to the initial containing block, which is usually the viewport.
position: fixed
Like absolute, position: fixed removes the element from the document flow. The key difference is that its containing block is always the viewport by default. This means it does not scroll with the page; it stays in the same position relative to the browser window.
This is commonly used for headers, sidebars, or "scroll to top" buttons.
However, there's a major edge case that often trips up developers.
The fixed Position Edge Case:
A fixed element's containing block is not the viewport if any of its ancestors has a transform, perspective, or filter property set to anything other than none. In these cases, that ancestor becomes the containing block. This can cause a fixed element to scroll with the page when you don't expect it to.
Stop fighting with CSS positioning
The same video from Kevin Powell provides a perfect demonstration of this often-confusing behavior.
Watch from 15:31 to 20:50. Observe how the position: fixed button works as expected initially. Then, see how adding a perspective property to its parent (the footer) changes its containing block and breaks the 'fixed' behavior. This is the kind of deep, conceptual 'gotcha' that is valuable to understand.
position: sticky
position: sticky is a hybrid. An element with this property behaves like position: relative until it reaches a specified offset (e.g., top: 0) as you scroll. At that point, it "sticks" and behaves like position: fixed, but only within the confines of its parent container.
Containing Block for sticky: A sticky item is constrained to its parent. It cannot leave the parent's content box. This is a key distinction from position: fixed, which is tied to the viewport.
This behavior also has common "gotchas" that are important to know.
Stop fighting with CSS positioning
Let's return to Kevin Powell's video for a final segment on the common issues encountered with sticky positioning.
Watch from 12:04 to 15:31. The video highlights two key reasons sticky positioning might fail: The sticky element is as tall as its parent (often a side effect of align-items: stretch in Flexbox or Grid), so there's no room for it to scroll and 'stick' within. The parent container itself is not tall enough to allow for scrolling.
Summary of Positioning Properties
Let's consolidate what we've learned.
| Property | Flow Behavior | Default Containing Block | Effect of top/left |
|---|---|---|---|
static |
In the normal flow | Content box of nearest block container | No effect |
relative |
In the normal flow, space is preserved | Content box of nearest block container | Offsets element from its original position |
absolute |
Removed from the flow | Padding box of nearest positioned ancestor | Positions element relative to the containing block |
fixed |
Removed from the flow | Viewport (unless an ancestor has transform, filter...) |
Positions element relative to the viewport |
sticky |
In the flow, then fixed within its parent | Content box of the parent element | Defines the 'sticking point' relative to the viewport |

Conclusion
You've now dissected the CSS position property through its most fundamental concept: the containing block. By understanding not just what each value does, but why it behaves that way based on its containing block, you've gained a much deeper and more resilient mental model for CSS layout.
Key Takeaways:
- The containing block is the essential context that determines a positioned element's size and placement.
position: relativekeeps an element in the flow but allows it to be shifted. Its main power is in creating a containing block forabsolutechildren.position: absoluteremoves an element from the flow and positions it relative to its nearest positioned ancestor.position: fixedremoves an element from the flow and positions it relative to the viewport, unless an ancestor has properties liketransformorfilter.position: stickyis a hybrid ofrelativeandfixed, but it is always confined within its parent's boundaries.
What's Next?
Using position: relative, absolute, fixed, and sticky often leads to elements overlapping. This raises a new question: how do we control which element appears on top? In the next lesson, we will explore this by diving into stacking contexts and the z-index property.