Technical note

Frosted glass traps your fixed overlays

One of our apps wears frosted-glass chrome. The header blurs whatever scrolls under it, the effect CSS calls backdrop-filter. We added a settings sheet to that header and gave it position: fixed, which is supposed to pin an element to the viewport no matter where it lives in the markup.

The sheet did not pin to the viewport. It pinned inside the header, clipped to the header's box, sitting on top of the brand mark. Same correct-looking CSS, wrong universe.

Fixed is only fixed to its containing block

position: fixed pins to the viewport only while no ancestor has claimed the element first. An ancestor with backdrop-filter becomes the containing block for its fixed descendants. filter and transform do the same thing. This is spec behavior, not a browser bug, and nothing warns you.

A fixed element is a nail you expect to drive into the window glass. Put a picture frame between the nail and the window, and the nail sinks into the frame. The element hangs exactly where you nailed it. The wrong thing is holding it.

So the moment we styled the header with glass, every fixed child inside it silently changed owners. The sheet was positioned perfectly, relative to a 64-pixel-tall box.

It bit us 3 times before the rule stuck

We fixed the settings sheet and moved on. Weeks later a chat drawer did the same thing. Then a bottom tab bar. Three separate overlays, three debugging sessions, one cause. The lesson was not the CSS fact, which we knew by round two. The lesson was that we kept building overlays inside the glass and trusting fixed to escape it.

Portal to body by default

The fix is to render the overlay as a child of document.body, outside every glass ancestor. In React that is createPortal(overlay, document.body). Gate it behind a mounted flag set in useEffect, so server rendering skips it and hydration stays clean. Outside React, append the overlay node to body and position it from there.

Our rule now: in any codebase with backdrop-filter in the chrome, every fixed drawer, sheet, and bar portals to body. Not after it breaks. By default.

And when a fixed element lands somewhere strange, grep the stylesheet for backdrop-filter, filter, and transform before you touch the overlay's own CSS. The bug is almost never in the element. It is in an ancestor that quietly adopted it.

Glass looks great. Just stop nailing things to it.