gotchacssModeratepending
Gotcha: CSS transform breaks position fixed children
Viewed 0 times
transformposition-fixedcontaining-blockviewportportal
Error Messages
Problem
A position: fixed element stops being fixed relative to the viewport when an ancestor has a CSS transform.
Solution
Any ancestor with transform, filter, or perspective creates a new containing block for fixed descendants:
/ This breaks fixed positioning: /
.parent {
transform: translateX(0); / Even identity transform! /
}
.child {
position: fixed; / Now fixed relative to .parent, not viewport /
top: 0;
}
Workarounds:
<div class="transformed">...</div>
<div class="fixed-element">...</div> <!-- Sibling, not child -->
const rect = element.getBoundingClientRect();
// Manually position based on viewport coords
- transform (any value, even none!)
- filter
- perspective
- will-change: transform
- contain: paint
- backdrop-filter
Render the fixed element at document.body level via portal
/ This breaks fixed positioning: /
.parent {
transform: translateX(0); / Even identity transform! /
}
.child {
position: fixed; / Now fixed relative to .parent, not viewport /
top: 0;
}
Workarounds:
- Move the fixed element outside the transformed ancestor:
<div class="transformed">...</div>
<div class="fixed-element">...</div> <!-- Sibling, not child -->
- Use JavaScript to calculate position:
const rect = element.getBoundingClientRect();
// Manually position based on viewport coords
- Use position: sticky as alternative (if applicable)
- Properties that create new containing block:
- transform (any value, even none!)
- filter
- perspective
- will-change: transform
- contain: paint
- backdrop-filter
- Portal pattern (React/Vue):
Render the fixed element at document.body level via portal
Why
Per CSS spec, a transform on an ancestor establishes a new containing block, overriding the viewport as the reference for fixed positioning.
Revisions (0)
No revisions yet.