Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-positioning] position: fixed within a stacking context #400

Open
valdrinkoshi opened this issue Aug 12, 2016 · 14 comments
Open

[css-positioning] position: fixed within a stacking context #400

valdrinkoshi opened this issue Aug 12, 2016 · 14 comments

Comments

@valdrinkoshi
Copy link

The spec of position: fixed specifies that:

Fixed positioning is similar to absolute positioning. The only difference is that for a fixed positioned box, the containing block is established by the viewport.

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,output

  <style>
    .container {
      border: 1px solid gray;
      width: 200px;
      height: 200px;
      overflow: auto;
      transform: translateZ(0);
    }

    .tall {
      height: 400px;
    }

    .fixed {
      position: fixed;
      padding: 20px;
      top: 80px;
      left: 80px;
      width: 150px;
      background-color: orange;
    }
  </style>

  <div class="container">
    <div class="tall"></div>
    <div class="fixed">
      I should not scroll! <br>
      I should not get clipped!
    </div>
  </div>

Resulting in
screen shot 2016-08-11 at 7 12 02 pm

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 the transform: translateZ(0) of .container)

screen shot 2016-08-11 at 7 12 10 pm

@upsuper
Copy link
Member

upsuper commented Aug 14, 2016

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.

@valdrinkoshi
Copy link
Author

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 not
  • perspective: safari crops the orange box, while chrome & ff will make it scroll
  • will-change: safari & ff don't crop neither scroll the orange box, chrome renders it behind the scrollbar

I'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?

@upsuper
Copy link
Member

upsuper commented Aug 15, 2016

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.

@upsuper
Copy link
Member

upsuper commented Aug 15, 2016

cc @grorg @smfr for the issue of perspective property mentioned above.

@valdrinkoshi
Copy link
Author

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:
screen shot 2016-08-15 at 4 46 01 pm

@upsuper
Copy link
Member

upsuper commented Aug 15, 2016

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.

@mstange
Copy link

mstange commented Aug 16, 2016

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.)

@valdrinkoshi
Copy link
Author

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 😞

@upsuper
Copy link
Member

upsuper commented Aug 16, 2016

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.

@valdrinkoshi
Copy link
Author

valdrinkoshi commented Aug 16, 2016

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?

@upsuper
Copy link
Member

upsuper commented Aug 16, 2016

No, and I don't think we want that actually. Top layer is a rather hacky thing initially created for fullscreen.

@dbaron dbaron added the css-position-3 Current Work label Sep 28, 2016
@oriadam
Copy link

oriadam commented Jan 2, 2018

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.

@tabatkins
Copy link
Member

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.

@smfr
Copy link
Contributor

smfr commented Apr 29, 2020

Cropping of position:fixed inside stacking-context with overflow:hidden or scroll is a WebKit bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants