Open valdrinkoshi opened 8 years ago
This behavior is speced in CSS Transforms spec that:
For elements whose layout is governed by the CSS box model, any value other than
none
for the transform results in the creation of both a stacking context and a containing block. The object acts as a containing block for fixed positioned descendants.
Thanks for the pointer @upsuper. There are several css properties that create a new stacking context, between them position: fixed
itself.
It is not obvious what would be the outcome in situations where a position: fixed
element is contained into a stacking context that is not the root stacking context.
What I ended up doing is trying all these css properties and see what's the behavior on the different browsers; FWIW here's my findings on creating a stacking context on .container
through:
opacity, position, mix-blend-mode, fliter
: safari will crop the orange box, while chrome & firefox will notperspective
: safari crops the orange box, while chrome & ff will make it scrollwill-change
: safari & ff don't crop neither scroll the orange box, chrome renders it behind the scrollbarI'm not sure if these are bugs or by design, and couldn't easily find the spec that defines the desired behavior. Any pointer would be greatly appreciated :)
Would it be possible to at least mention that position: fixed
elements are affected by stacking contexts of their parents?
opacity
,position
,mix-blend-mode
,fliter
: safari will crop the orange box, while chrome & firefox will not
This is a bug of Safari. Those properties only create a stacking context, and do not act as a containing block for fixed positioned descendants.
perspective
: safari crops the orange box, while chrome & ff will make it scroll
Looks like the spec isn't clear that perspective
property should act as a containing block for fixed positioned descendants, but I suppose it should because it should have same behavior as perspective()
function for transform
.
Safari's behavior here looks buggy either way, though.
will-change
: safari & ff don't crop neither scroll the orange box, chrome renders it behind the scrollbar
will-change
has different behavior when it has different values. What will-change
value are you referring to here?
Specifying will-change: transform
makes it work like transform: xxx
, in both Firefox and Chrome, and Safari's behavior again looks buggy.
You can find the spec of behavior of will-change
in CSS Will Change spec.
cc @grorg @smfr for the issue of perspective
property mentioned above.
will-change
has different behavior when it has different values. What will-change value are you referring to here?
I've been playing with will-change: opacity
http://jsbin.com/kigiqi/2/edit?html,output, and on chrome it gets rendered behind the scrollbar:
That is a bug of Chrome then, as will-change: opacity
should be effectively identical to specifying opacity
to a value smaller than 1
in terms of positioning.
opacity, position, mix-blend-mode, fliter: safari will crop the orange box, while chrome & firefox will not
When you checked position
, did you include a test for position: sticky
?
position: sticky
does not establish a containing block for fixed positioned descendants, but if I recall correctly, it clips in all browsers except Firefox at the moment. (As an aside, I'd like to change Firefox's behavior to match the other browsers', because it makes the implementation a little simpler.)
My tests were done with position: fixed
on .container
.
I just tried with position: sticky
and see cropping only on safari http://jsbin.com/zivofer/2/edit?html,output
Aside: I'm working on an overlay custom element; it should be capable of rendering on top of the other content when opened (like <dialog>, <select>
, or the tooltips rendering the alt
attribute value). I rely on position: fixed
to have it positioned in the viewport and z-index
for rendering on top of the content. The above mentioned native elements (dialog, select) are stacking-context agnostic, in the sense that are not cropped, nor participate to the scrolling, and are always rendered on top of everything. I couldn't find a way to access to this magic through css yet, the only way is to ask the users of my element to declare it in a stacking-context-safe parent 😞
No, there is no such magic thing in CSS. Some DOM APIs use a concept of top layer for putting things on the very top, which is not available in CSS, though.
It would be pure gold to have access to the top layer stack (e.g. add/remove nodes via DOM APIs would be more than enough) 😄 Is there any WIP around it, or an issue where to follow updates?
No, and I don't think we want that actually. Top layer is a rather hacky thing initially created for fullscreen.
A position that is relative to viewport is necessary.
Solution proposal: position: viewport
in which the containing block is established by the viewport, regardless of stacking.
Another proposal: position: #element-id
in which the containing block is a specific element. This way designers could attach tooltips and floating menus to elements or rows without having to use JS and listen to scrolls and element position changes.
Circular definition can be a problem.
As far as I can tell, nothing here is an error in the Position spec, it's just a pile of browser bugs wrt what properties create fixed positioning containing blocks, and how to respond to that.
So just marking as Needs Testcase to make sure these cases are exercised in WPT.
Cropping of position:fixed inside stacking-context with overflow:hidden or scroll is a WebKit bug.
The spec of
position: fixed
specifies that:https://www.w3.org/TR/css-position-3/#fixed-pos https://www.w3.org/TR/css-position-3/#containing-block
But it is not obvious what happens if a
position:fixed
element is contained in a parent that creates a stacking context. What happens is that the fixed element participates to the scroll and gets clipped http://jsbin.com/kehexi/3/edit?html,outputResulting in
Is this an expected behavior for
position: fixed
? From the spec, I'd expect it to render in the top stacking context and not participate to the scrolling (e.g. comment thetransform: translateZ(0)
of.container
)