Position fixed and CSS transforms


An HTML element with position: fixed will lose its fixed positioning if a CSS transform is applied to its ancestors. Remove all transforms from ancestors to recover fixed positioning.

I had a long standing and mysterious bug in Birdview.js (press Z or pinch-in to see Birdview in action): after activating Birdview, elements with position: fixed would no longer stay fixed relative to the viewport.

Recently, I stumbled on a compilation of tips by Claus Wahlers to make something 100% height on Mobile Safari. I came across this bit:

If positioning turns out not to be relative to the viewport, you probably have a transform applied on an ancestor, and your element is positioned relative to that ancestor’s bounds.

Here’s the full quote from the W3C spec:

For elements whose layout is governed by the CSS box model, any value other than none for the transform also causes the element to become a containing block, and the object acts as a containing block for fixed positioned descendants.

Indeed! That’s what’s happening with Birdview.js!

Birdview applies a CSS scale and translate to 2 containers that wrap the whole document. When the user exits Birdview, the wrappers are set back to scale(1) and translateY(0px). But even an identity transform is still a transform. So any element with position: fixed would become fixed relative to the wrappers instead of the viewport.

I could rewrite the JavaScript calls to set back the wrappers to transform: '', but I need to set a specific value to get back to, so that all browsers can correctly interpolate and animate the transition.

The solution is to remove CSS transforms only after the transition ends, using the transitionend event:

wrapper.addEventListener("transitionend", function(){
    wrapper.style.transform = '';
}, false);


The Quotes page demonstrates the behavior:

screenshot of the quotes web page
The list on the left has position: fixed. It wouldn’t stay fixed before the fix. Now it sticks to the viewport even after calling Birdview.
screenshot of a birdview of the quotes web page
Notice that while in Birdview, the list sticks to the upper bound of the document! That’s because CSS transforms are applied, and the list is fixed relative to the wrapper. Fixed positioning relative to the viewport is recovered after the user exits Birdview and the CSS transition ends.