w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.44k stars 656 forks source link

[css-overflow] add method to prevent elements from contributing to scrollable overflow #8361

Open johannesodland opened 1 year ago

johannesodland commented 1 year ago

https://www.w3.org/TR/2022/WD-css-overflow-3-20221231/#scrollable

Motivation

Sometimes it's useful to prevent elements from contributing to the scrollable overflow area. In particular elements that exist for purely decorative purposes. This could i.e. be elements that are animated in the background with 2d or 3d transforms.

For elements not participating in a 3D rendering context its possible to eliminate them from contributing to the scrollable overflow area by adding contain: paint, overflow: hidden or overflow: clip to a parent, effectively clipping them away.

This is not a workable strategy for elements participating in a 3D rendering context. contain: paint, overflow: hidden and overflow: clip are all grouping property values, and will force the parent element to have a used style of flat for preserve-3d. This effectively separates the elements from the 3d rendering context they were participating in.

Proposal

Add a method to prevent elements from contributing to scrollable overflow. This could be a new property such as overflow-contribution: normal | none.

Alternative solutions

Allow a way of clipping overflow that is not a grouping property value and does not force a used style of flat for preserve-3d.

It seems like there's no interop on contain: paint forcing used style of flat for preserve-3d. WebKit does force flat, while Blink and Gecko does not seem to force flat at the moment.

An alternative solution would be remove contain: paint from the grouping property values.

Example

<div class="parallax-scroll-container">
  <div class="decorative-element">...</div>
  ...
</div>
.parallax-scroll-container {
  perspective: 100px;
  overflow: auto;
}

/* 
This element will extend the scrollable overflow area, and using a parent to clip it 
will prevent it from participating in the perspective transformed 3d rendering context 
*/
.decorative-element {
  --depth: 1.5;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 200vh; /* Arbitrary height taller than content */
  transform: translateZ(calc(-100px * (var(--depth) - 1)))
    scale(calc(var(--depth)));
  transform-origin: 50vw 50vh;
}
jonjohnjohnson commented 1 year ago

Could be worth keeping #3322 in mind here.

LeaVerou commented 1 year ago

Some more discussion in https://github.com/w3c/csswg-drafts/issues/8400, which is closed as a duplicate.

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed [css-overflow] add method to prevent elements from contributing to scrollable overflow, and agreed to the following:

The full IRC log of that discussion <fantasai> See also leaverou's examples in https://github.com/w3c/csswg-drafts/issues/8400
<dael> TabAtkins: Happy to take it since raised by non-WG and leaverou is not available
<dael> TabAtkins: Request is some way of opting an element out of contributing to ancestor scrollable overflow. Lots of examples of places with decorative element that happens to overflow and element a little bit. Overflow isn't important. Stuff in viewport is important but you trigger scrollbars
<dael> TabAtkins: Example from leaverou is the fork me banner on GH that's at 45 deg angle and has a little corner poke out. Another example is animating an element into the page it's outside the page as it animates in, triggers scrollbars, but once it's in place no scrollbars.
<iank_> q+
<dael> TabAtkins: Forcing an element to only contribue ink overflow. More to discuss about using it in a safe fasion, but use case is worth addressing and should explore in overflow 4
<Rossen_> ack iank_
<dael> iank_: Trivial for implementation, more or less what we do for position:fixed already. Want to make sure this doesn't effect the content-edge contribution to scrollable overflow. I don't think that breaks any use cases
<dael> iank_: If you have element in block flow at the end the end content edge contributes to scrollable overflow, but when you rotate the element wouldn't. Want to make sure of that. Otherwise, this would be great
<dael> TabAtkins: More details on the case?
<dael> iank_: Maybe grid is easier to explain. The content-edge- we add the end content edge; padding after content edge; as scrollable overflow. To do taht look at where children are or look at grid itself. Grid, see last row and column, add end padding, and that's part of scrollable overflow
<dael> iank_: If we start excluding things from the content-edge calc it gets tricky very quickly
<dael> TabAtkins: Do we currently pay attention to things like box shadow for that calc?
<dael> fantasai: No b/c ink overflow
<dael> TabAtkins: Assume similar here
<dael> fantasai: I think iank_ is saying there are things not descendant boxes that are for scrollable overflow and we shoudln't change that?
<dael> iank_: Correct. When calc overflow we factor in a bnch of things like where the padding is. Don't want to effect that calculation
<dael> fantasai: I agree and I don't think that's requested. Need to set on the element containing the padding. You'd like to set on an element whose ancestor is a scrollable
<dael> iank_: A bit of a nuance b/c could say you shouldn't include me where the content edge is but want the distinction
<dael> fantasai: I think if we add it's a property on an element you want to exclude that says ignore me when calc scrollable overflow
<dael> fantasai: Might want a distinction between ignore my box but pay attention to my contents vs ignore me and all my contents. I can imagine a rotated box with padding where you don't care about corners but you do want the text scrollable
<dael> fantasai: Prop 3 values, One is normal, one is ignore my box, one is ignore me and all my descendants
<dael> TabAtkins: Makes sense
<dael> iank_: Want to check with authors on more complex. It sounds fine
<flackr> Sounds reasonable. Could allow setting the not ignored property on a descendant for some of those descendant cases
<dael> Rossen_: Clarification - assuming this is true for my immediate scrollport ancestor and all of it's ancestors? Including initial?
<dael> TabAtkins: Yep. Ideal is you markt he element as ink overflow so it's the same as ink overflow in all scrollers
<dael> TabAtkins: iank_ hypotheitical. Animating element up from bottom to visible. I have this marked on it. Do you think okay or would it make scrollbars?
<dael> iank_: If it's out of flow positioned behaves as you expect. If it's in flow you would still consider end content edge
<dael> TabAtkins: That sounds good. We'll have to make sure we get that b/c it's a little more nuanced, but I think it's fine. Will need to word carefully.
<Rossen_> q?
<Zakim> fantasai, you wanted to ask about element vs descendant content
<dael> iank_: fwiw if we can come up with a reasonable syntax this is trivial to impl
<dael> fantasai: Name is had. overflow-skip?
<fantasai> s/had/hard/
<dael> TabAtkins: We can do names in the thread
<dael> Rossen_: Overall sentiment is we want to resolve on adopting the feature and figure out name as we go. Anything else to talk about or resolve on this?
<dael> TabAtkins: That's all
<dael> Rossen_: Obj on Adopt this feature as overflow-bikeshed
<dael> RESOLVED: Adopt this feature as overflow-bikeshed
argyleink commented 9 months ago

overflow-transform: clip
overflow-clip-transform: contain
transform-clip: overflow

dbaron commented 9 months ago

Some more naming possibilities (some of which are from or partly from the discussion above; I didn't see any in #8400) include (listing the initial value first):

bfgeek commented 9 months ago

One thing that I've heard from developers is a desire just to skip the transform adjustment that happens. E.g. something that could be useful is:

overflow-contribution: normal | none | ignore-transform

dbaron commented 9 months ago

(see also #9458 about defining exactly what transform adjustment happens!)

LeaVerou commented 9 months ago

One thing that I've heard from developers is a desire just to skip the transform adjustment that happens. E.g. something that could be useful is:

overflow-contribution: normal | none | ignore-transform

If this is about elements being moved by transforms triggering overflow, it's not exclusive to transforms, it also applies to positioning.

flackr commented 6 months ago

If this property affects scrollable overflow, it should probably also affect scrolling related APIs and snap areas. E.g. I could see overflow-contribution: ignore-transform being really useful to:

As such, maybe the name needs to be more generic like overflow-box?

bfgeek commented 4 months ago

Adgenda+ to paint the bikeshed on a name for this property.

css-meeting-bot commented 3 months ago

The CSS Working Group just discussed [css-overflow] add method to prevent elements from contributing to scrollable overflow.

The full IRC log of that discussion <emeyer> iank_: Developers would like a mechanism to ignore elements from scrollable overflow
<emeyer> …We also heard suggestions to ignore transforms for scrollable overflow purposes
<flackr> q+
<emeyer> …I think the only blocking thing here is, what do we call this?
<emeyer> …It's trivial to implement
<astearns> ack flackr
<emeyer> flackr: I raised the point there are parts of overflow that are significant
<emeyer> …I think it makes a big different for the name whether we include those or not
<emeyer> …That's why I suggested overflow-box
<emeyer> …Do we want to include snapping scroll into view
<emeyer> iank_: The specific case here is that a major site, because Chrome does transforms slightly more correctly, we snap to a transformed element which isn't the correct place
<emeyer> …The site wants to snap to the non-transformed place
<florian> q?
<emeyer> …We're only seen this with transforms; one option is to have a different property that says to ignore transforms for a bunch of operations
<emeyer> astearns: My concern is that you aren't defining a box, you're defining what the box pays attention to and what it ignores
<emeyer> …overflow-box-contribution seems more precise
<emeyer> iank_: I worry people will think it refers to which box model box you're using
<miriam> q+
<emeyer> flackr: I don't care about the name that much as long as we include those additional behaviors
<emeyer> …We do get into cases where we use a transform and get unstab le scroll position as a result
<emeyer> iank_: I think we use one or two properties
<emeyer> …The first property would just ignore transforms for snap alignement, scroll into view
<florian> q?
<florian> q+
<emeyer> …The second would ignore scrollable overflow contributions completely for the element
<astearns> ack miriam
<emeyer> flackr: Should decide if that should be two properties or two values on one proeprty
<emeyer> miriam: How does it work what it's in flow?
<emeyer> …If you set it to none, and it's the last thing on an autoflow, it doesn't trigger scrollbars
<emeyer> …But if you have something after it, it does?
<emeyer> iank_: If it's in flow, the in flow padding edge wraps everything onthe top layer and will still be scrollable
<emeyer> …Won't remove all side effects completely, but removes direct contribution of that element
<emeyer> …People can abspos things somewhere and it doesn't contribute
<astearns> ack florian
<emeyer> florian: If we go with two proeprties, the one that controls taking transforms into account probably shouldn't havce the word transform in its name
<emeyer> …You might want the behavior for more than transforms
<ydaniv> how about something like `layout-box`?
<flackr> q+
<emeyer> iank_: Initially, I wouldn't want to include relpos until we get stronger signals, since it's not as cleanly separated as transforms
<astearns> ack dbaron
<emeyer> florian: Sure, I just don't want to pick a name that would preculde handling that later
<khush> q+
<emeyer> dbaron: Agreed; there are cases where people want to ignore the transform while also using features you think they want to ignore
<astearns> ack flackr
<dbaron> s/want/might want/
<emeyer> flackr: More complicated answer is to ignore the animated value
<emeyer> …That wouldn't ignore scripted cases, and would be harder to compute, but
<khush> q-
<emeyer> iank_: I've thought about that case and I don't think we want to go down that path
<emeyer> flackr: Agreed
<astearns> ack fantasai
<emeyer> astearns: Sounds like we're at a single proeprty with multiple values
<emeyer> fantasai: For relpos situations, they could use transforms, so covering that covers most cases, I think
<emeyer> iank_: I'm coming around to this being two properties… but we still don't have any good names
<emeyer> astearns: What would the two properties do?
<emeyer> iank_: One switches off direct scrollable overflow contribution entirely, with values like normal and none
<fantasai> overflow-visibility: normal | none | transforms
<emeyer> …The other would affect things like snap align, scroll into view ignoring transforms
<emeyer> astearns: And the second one, you'd still have a scrollbar?
<emeyer> flackr: That would also be affected by the change in interpretation
<emeyer> …If you said you were ignoring transitions, you wouldn't get a scrollbar to scroll to the transformed position
<emeyer> astearns: Ian said this wasn't about the creation of the scrollable area; the first proeprty is the one that defines that
<fantasai> contain: overflow? transform-overflow: normal | none?
<emeyer> flackr: We can treat whether we're contributing as a separate thing
<emeyer> astearns: Then I don't get why they need to separate
<emeyer> iank_: It is a separate thing
<emeyer> …The first covers everything, and the second says "only ignore transform"
<khush> q+
<emeyer> ydaniv: We could use 'ignore-transforms' and something like layout
<emeyer> fantasai: I don't understand why they need to be separate either
<emeyer> iank_: The second affects things like snap areas
<ydaniv> s/and something/or something/
<dbaron> s/affects/also affects/
<emeyer> …If you use one property, what happens if you say none and it's a snap area
<emeyer> …The first property only makes sense for scrollable overflow
<emeyer> …The second would address other things
<emeyer> fantasai: None of that invalidates my question
<emeyer> iank_: What happens to all the things what you set to none?
<florian> q+
<emeyer> flackr: What if instead of none, you have a value of clip, which means it's scrollable rect limits to the scrollable area
<emeyer> iank_: You might have other things, so I don't think that wil work
<emeyer> flackr: Let's say overflow-contribution: none, and you try to scroll to this box that hasn't contributed to scrollable area, but it isn't reachable because the scrollable area hasn't included that
<emeyer> iank_: I'm not sure what I would expect to happen there, so a way we could design it is it doesn't produce a snap area
<emeyer> …I worry, but the flip side is you might be able to see it because the padding box is big enough to see it, and what happens then?
<emeyer> flackr: This is why I was suggesting clipping
<khush> q-
<emeyer> iank_: I don't think that works but it's a complicated answers based in order of operations on rectangle computation
<astearns> ack florian
<emeyer> florian: It makes sense as separate properties because you'd want to set them separately at least some of the time
<emeyer> …You might want to say "don't show scrollbars" in one place, but in another place you say to snap to where a thing would be
<emeyer> …Having one reset the other might work out fine, but I'm not sure
<emeyer> …I lean toward separate properties
<emeyer> astearns: I'm not hearing consensus on how many properties there should be, so we should go back to the issue because we aren't ready to bikeshed
<florian> s/snap to where a thing would be/snap to where a thing would be if it weren't transformed
<emeyer> flackr: We should write up the alternatives and use cases so we can figure this out
<fantasai> scroll-visibility and transform-overflow?
<emeyer> iank_: That sounds fine, so folks can have a think
<emeyer> …We have been hearing about this in conversations with devs, so it would be good to address this
<fantasai> overflow-ignore: self | transforms | normal
<emeyer> …Handling it is pretty easy, so we just need to design it
<emeyer> astearns: Agreed
fantasai commented 3 months ago

I think for the purpose of learnability, it would be better to have this as one property rather than two.

flackr commented 3 months ago

To summarize the discussion, there are two behaviors being discussed here:

  1. Whether or not a given element contributes to the scrollable overflow.
  2. What the used rectangle for scrollable overflow and scrolling operations for this element should be. E.g. should it ignore the element's transform.

I think we are all agreed that these are both valuable behaviors to be able to control. The main point of contention was whether this would be 1 or 2 properties. To help I'll suggest possible properties / values (of course welcome bikeshedding).

As one property, this would look something like this:

overflow-contribution: normal | ignore-transform | none;

The question is if we specify none, what are the effects on scrolling / snapping operations? Would we prevent snapping / scrolling to this element? If not, what if you want the element to not contribute to scrollable overflow and ignore transforms for scroll related operations? A counter-point to this, is when you want to not contribute to scrollable overflow, the UA won't guarantee that this element is reachable which may mean that the developer doesn't intend the user to need to scroll to this element, so maybe it would be reasonable to treat the element as purely decorative?

As two properties, these would be specified independently, e.g.:

overflow-contribution: normal | none;
scroll-align: normal | ignore-transform;

Do all combinations of this make sense? Probably, you can imagine how these could be applied independently, but are there practical use cases where we want to scroll to an element that doesn't contribute to scrollable overflow? Perhaps an overly large image that you don't want to introduce horizontal scrolling for?

Alternately, a third option could be to have a single property with multiple values, but this may just suggest a need for multiple longhand properties, e.g.

overflow-contribution: <normal | none> || <auto | ignore-transform>?;
johannesodland commented 3 months ago

The question is if we specify none, what are the effects on scrolling / snapping operations? Would we prevent snapping / scrolling to this element?

Could we treat this similar to an element that is placed wholly or partly into the negative scrollable overflow region? Such an element won't extend the scrollable overflow area, and the used snap point for the element is the position resulting from scrolling as much as possible towards the desired snap point in the relevant axis?

Regarding snapping operations: there is a related issue https://github.com/w3c/csswg-drafts/issues/7885 containing use cases for extending the scrollable overflow area to make snap points reachable. Maybe that issue could be solved with the same property/-ies?