Rendering issue when using position:fixed with containing block

Discussions about the development and maturation of the platform code (UXP).
Warning: may contain highly-technical topics.

Moderators: trava90, athenian200

jez9999
Fanatic
Fanatic
Posts: 106
Joined: 2015-05-30, 19:35
Location: UK

Rendering issue when using position:fixed with containing block

Unread post by jez9999 » 2022-11-13, 19:17

For an example, see: https://game-point.net/misc/stickyMaskO ... index4.htm

When a div is created with 'position:fixed' inside a container div with 'transform:translate(0); overflow:auto; max-height:300px;', and it is then given a sibling div whose content causes the container to overflow, the 'fixed' div should not change its position when the overflowing content is scrolled, in the same way that it doesn't if the fixed positioning containing block is the viewport. However, when 'transform:translate(0)' is applied to the container to establish it as the fixed positioning containing block, the 'fixed' div starts to incorrectly become scrolled along with the overflowing content as if its positioning were set to 'absolute'.

Relevant part of the CSS spec: https://w3c.github.io/csswg-drafts/css- ... /#fixed-cb

Yes, all the major browsers get this wrong too. I've been developing a site recently and wanted it to create a 'mask' element, and discovered this. However I'm relatively sure that I'm reading the spec right. The 'fixed' element is getting its height from the container; it should therefore be positioned relative to it, not its content.

User avatar
Moonchild
Pale Moon guru
Pale Moon guru
Posts: 35404
Joined: 2011-08-28, 17:27
Location: Motala, SE
Contact:

Re: Rendering issue when using position:fixed with containing block

Unread post by Moonchild » 2022-11-13, 19:30

I think you're reading the spec wrong, or drawing the wrong conclusions from reading the spec right in terms of expected behaviour.

Keep in mind that what you will be scrolling will be the viewport, not the sibling element, if you create a stacking context by using transform and creating new containing elements that way. I.e. you are scrolling the entire overflowed contents that in itself has become fixed by being its own stacking context (and lifted out of the page). As far as i can tell it is exactly supposed to act that way.

If you want a sticky header, why aren't you just using the CSS keyword that was explicitly introduced for this kind of thing, position:sticky?
"Sometimes, the best way to get what you want is to be a good person." -- Louis Rossmann
"Seek wisdom, not knowledge. Knowledge is of the past; wisdom is of the future." -- Native American proverb
"Linux makes everything difficult." -- Lyceus Anubite

jez9999
Fanatic
Fanatic
Posts: 106
Joined: 2015-05-30, 19:35
Location: UK

Re: Rendering issue when using position:fixed with containing block

Unread post by jez9999 » 2022-11-13, 19:57

Moonchild wrote:
2022-11-13, 19:30
I think you're reading the spec wrong, or drawing the wrong conclusions from reading the spec right in terms of expected behaviour.

Keep in mind that what you will be scrolling will be the viewport, not the sibling element, if you create a stacking context by using transform and creating new containing elements that way. I.e. you are scrolling the entire overflowed contents that in itself has become fixed by being its own stacking context (and lifted out of the page). As far as i can tell it is exactly supposed to act that way.
Erm, sorry but that description is.... extremely confusing. An overflowed contents is its own stacking context?

The way I see it, a fixed element has its top, left, width, and height defined in terms of its fixed positioning containing block. By default, that's the viewport. So if the element has 100% width and height, and 0 for left and top:

1) The element's fixed positioning containing block is the viewport.
2) The viewport overflows, causing it to get a scrollbar. The element's position is 0,0 because the viewport's position is 0,0. The viewport content's position is 0,0.
3) The scrollbar is used and moved down 100 pixels. The element's position is 0,0 because the viewport's position is 0,0. The viewport content's position is 0,-100px.

The above is in line with the spec and is the behaviour of all browsers, causing the element to appear fixed relative to the viewport. Now we establish our container div as the fixed positioning containing block. Can we not just replace the word "viewport" with "container" above? If the container happens to be at 50,50 (maybe because of body margin, say):

1) The element's fixed positioning containing block is the container.
2) The container overflows, causing it to get a scrollbar. The element's position is 50,50 because the container's position is 50,50. The container content's position is 50,50.
3) The scrollbar is used and moved down 100 pixels. The element's position is 50,50 because the container's position is 50,50. The container content's position is 50,-50px.

That should cause the element to appear fixed relative to the container, and not scroll with the content. Where did I go wrong?
If you want a sticky header, why aren't you just using the CSS keyword that was explicitly introduced for this kind of thing, position:sticky?
Because I don't really want a sticky header, I want a mask overlay on top of the content (I could also see a use-case for some kind of widget to be kept-in-place relative to the box whilst content is scrolled inside a box). Sticky doesn't remove the mask from the flow, and so displaces the rest of the content.

User avatar
Moonchild
Pale Moon guru
Pale Moon guru
Posts: 35404
Joined: 2011-08-28, 17:27
Location: Motala, SE
Contact:

Re: Rendering issue when using position:fixed with containing block

Unread post by Moonchild » 2022-11-13, 21:08

I'll try to clarify:
When you create a stacking context, it is, as I said, lifted out of normal document flow from a layout perspective.
position:fixed does this on its own, as well.
A stacking context will treat whatever is in it as its own thing, and for the rest of the document, the stacking context itself is a single item.
So what happens here is, that the fixed position overlay AND the sibling element that ends up under it, together, become a single scrollable item when it is "lifted out" into a containing block that has overflow scrolling.

In effect, you have 3 containing blocks. One being the fixed positioned overlay, one being the fixed positioned overlay and its sibling, and once being the top-level document. in general, when issuing scrolling events, they are passed top-down in the hierarchy "when it can't scroll (any further)", if I remember the layout logic correctly. So it will be scrolling the content block containing both overlay and sibling (since that has an overflow and can scroll) and not the (lower level) sibling under the overlay (sicce that is not constrained and effectively fixed as a result).

Does that help?
jez9999 wrote:
2022-11-13, 19:57
I want a mask overlay on top of the content (I could also see a use-case for some kind of widget to be kept-in-place relative to the box whilst content is scrolled inside a box).
Just use a position:fixed block then, and don't create a separate containing block around it. If you still need that, then make sure your overflow: property is set on the correct element so you're forcing only the scrolling content to scroll and keeping everything else standard content without overflow.
"Sometimes, the best way to get what you want is to be a good person." -- Louis Rossmann
"Seek wisdom, not knowledge. Knowledge is of the past; wisdom is of the future." -- Native American proverb
"Linux makes everything difficult." -- Lyceus Anubite

jez9999
Fanatic
Fanatic
Posts: 106
Joined: 2015-05-30, 19:35
Location: UK

Re: Rendering issue when using position:fixed with containing block

Unread post by jez9999 » 2022-11-13, 22:14

Moonchild wrote:
2022-11-13, 21:08
I'll try to clarify:
When you create a stacking context, it is, as I said, lifted out of normal document flow from a layout perspective.
position:fixed does this on its own, as well.
A stacking context will treat whatever is in it as its own thing, and for the rest of the document, the stacking context itself is a single item.
So what happens here is, that the fixed position overlay AND the sibling element that ends up under it, together, become a single scrollable item when it is "lifted out" into a containing block that has overflow scrolling.

In effect, you have 3 containing blocks. One being the fixed positioned overlay, one being the fixed positioned overlay and its sibling, and once being the top-level document. in general, when issuing scrolling events, they are passed top-down in the hierarchy "when it can't scroll (any further)", if I remember the layout logic correctly. So it will be scrolling the content block containing both overlay and sibling (since that has an overflow and can scroll) and not the (lower level) sibling under the overlay (sicce that is not constrained and effectively fixed as a result).

Does that help?
Holy heck that's complicated. I guess if it does "combine everything into one" that behaviour makes sense but I don't know why they designed it that way.
jez9999 wrote:
2022-11-13, 19:57
I want a mask overlay on top of the content (I could also see a use-case for some kind of widget to be kept-in-place relative to the box whilst content is scrolled inside a box).
Just use a position:fixed block then, and don't create a separate containing block around it. If you still need that, then make sure your overflow: property is set on the correct element so you're forcing only the scrolling content to scroll and keeping everything else standard content without overflow.
But how can I do that without using JS or something to calculate the element I want the mask to overlay? The element is having its size calculated by the browser, I'm not setting explicit sizes. If I have an element whose position is fixed it's just positioned relative to the viewport... how can I get that to overlay the scrollable content?

User avatar
Moonchild
Pale Moon guru
Pale Moon guru
Posts: 35404
Joined: 2011-08-28, 17:27
Location: Motala, SE
Contact:

Re: Rendering issue when using position:fixed with containing block

Unread post by Moonchild » 2022-11-13, 22:38

Holy heck that's complicated. I guess if it does "combine everything into one" that behaviour makes sense but I don't know why they designed it that way.
If you don't design it that way, then all the fancy CSS "free layout" that takes document elements out-of-flow would not be possible.
But yeah it gets really complicated. That's why maintaining and updating a browser layout engine is not trivial.

Actually, you can use position:absolute for this. Sorry I'm not doing CSS daily at the moment so it's not ready forefront knowledge.
By setting pointer-events:none you prevent mouse interaction with the overlay.

Here's a working example (taken from https://stackoverflow.com/a/74376689/2091005 where your question asked by YOU was already answered... days ago. Why exactly did you want me to spend time on this?):

Code: Select all

<html><head>
<style>
div {
    border: 0;
    padding: 0;
    margin: 0;
}

#stickyMask {
    position: absolute;
    top: 0;
    background-color: #2ecc71;
    text-align: center;
    width: 100%;
    height: 80px;
    opacity:0.5;
    font-size: x-large;
    font-weight: bold;
    pointer-events: none;
}

.container {
    height: 250px;
    position: relative;
}

.content {
    height: 100%;
    overflow: auto;
}
</style>
</head>
<body>
<h2>Below is some masked scrollable content:</h2>

<div class="container">
  
    <div id="stickyMask">
        Green mask using sticky positioning inside a container
    </div>
  
  <div class="content">
    <h3>
      Content which overflows and scrolls
    </h3>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </p>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </p>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </p>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </p>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </p>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </p>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </p>
  </div>
</div>
</body>
</html>
"Sometimes, the best way to get what you want is to be a good person." -- Louis Rossmann
"Seek wisdom, not knowledge. Knowledge is of the past; wisdom is of the future." -- Native American proverb
"Linux makes everything difficult." -- Lyceus Anubite

jez9999
Fanatic
Fanatic
Posts: 106
Joined: 2015-05-30, 19:35
Location: UK

Re: Rendering issue when using position:fixed with containing block

Unread post by jez9999 » 2022-11-13, 23:14

... and you'll see I replied to it saying that the problem with that solution is that because the overflow is happening on the content and not the wrapper, the mask overlays the scrollbar when I don't want it to. :)

That said, I'm just about to mark this answer on there as correct with a little edit because I've just discovered that that's actually the way to achieve what I want, and having re-read the grid spec on that it does appear to actually be by design (previously I had thought it a quirk of Chrome's rendering). The edit needed is that Firefox has a bug right now that means grid-template-rows: 100%; doesn't achieve the calculated grid height (it should), but for some reason the equivalent grid-template-rows: minmax(0, 1fr); works fine!

It also works in Pale Moon although oddly Pale Moon renders a disabled horizontal scroll bar until the window is resized, whereupon it disappears. So I guess I am reporting a rendering bug after all! 8-)

Demo: https://game-point.net/misc/stickyMaskO ... index5.htm

User avatar
Moonchild
Pale Moon guru
Pale Moon guru
Posts: 35404
Joined: 2011-08-28, 17:27
Location: Motala, SE
Contact:

Re: Rendering issue when using position:fixed with containing block

Unread post by Moonchild » 2022-11-14, 01:32

Well there are many ways to achieve similar effects, all subtly different or in need of tweaks to achieve a very narrowly-specified result when you're trying to do very specific layout manipulation. Your initial report would have been a pretty major spec issue if it was true. A temporary scrollbar issue is going to be low priority since it doesn't actually break anything, so if you want to do some research and find out what would be the exact issue in code/bz bug/solution, then by all means feel free to assist.
"Sometimes, the best way to get what you want is to be a good person." -- Louis Rossmann
"Seek wisdom, not knowledge. Knowledge is of the past; wisdom is of the future." -- Native American proverb
"Linux makes everything difficult." -- Lyceus Anubite

Locked