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-scroll-snap] scroll-snap-padding vs scroll-padding #395

Closed
frivoal opened this issue Aug 10, 2016 · 10 comments

Comments

Projects
None yet
4 participants
@frivoal
Copy link
Collaborator

commented Aug 10, 2016

The section about scroll types distinguishes between 3 types of scrolling. The new prose looks better to me than the old one, but I am not satisfied that the issue I raised a while back is resolved, and I still see a distinction between explicit end positions and implicit end positions.

In the following cases, the user indicates an explicit end position:

  • a panning gesture, released without momentum
  • manipulating the scrollbar “thumb” explicitly
  • programmatically scrolling via APIs such as scrollTo()

In these following cases however, the user does not indicate an explicit end position, and instead, merely expresses the wish that the thing in question is brought to any position within an acceptable range. It is the UA, not the user, that decides, within this acceptable range, which specific end position we should go after.

  • tabbing through the document’s focusable elements
  • navigating to an anchor within the page
  • moving the caret in an editable element

Once the end position has been picked, I think I agree these two categories result in the same behavior. But the reason I believe it is useful to distinguish between them is that
there is something to be said in the spec about what the acceptable range is.

Specifically, I believe that this acceptable range should be the scroll snapport, not the scroll viewport. Now, to be fair, this picking of a position within the acceptable range isn't actually about snapping, and conceptually happens before the snapping logic kicks in.

Which leads me to believe that the scroll-snap-padding property should be renamed into scroll-padding, and in addition to doing what it is currently defined to do with regards to snapping, it should also define the acceptable range of end position from which the UA is free to pick when converting a user's implicit scroll request into an explicit end position to be the "scroll snapport", even if there is no snapping involved in any way, and even if scroll-snap-type is none.

Whether it is because the author wants to give some breathing room around the content, or to avoid having the content that has been scrolled / snapped into view to be obscured by a fix-pos overlay or similar, the use cases that justify having a non zero scroll-snap-padding when snapping are just as valid when no snapping is involved and we're dealing with implicit scrolls.

EDIT: fixed a few typos

@frivoal frivoal changed the title [css-scroll-snap] scroll-snap-padding vs scroll padding [css-scroll-snap] scroll-snap-padding vs scroll-padding Aug 10, 2016

@frivoal

This comment has been minimized.

Copy link
Collaborator Author

commented Aug 10, 2016

@fantasai

This comment has been minimized.

Copy link
Collaborator

commented Aug 16, 2016

Ok, correct me if I'm wrong, but the proposal here is to

  • Define scroll-snap-padding to provide a guideline of where in the viewport the focused content should go when scrolling to something on the page in general and not just when snapping a snappable element, since it is already designed to provide this guidance anyway.
  • Define “focused content” here to include a URL fragment's target area when navigating to that fragment [already in the spec], an element that is focused while off-screen (and therefore scrolled into view), a caret that is positioned off-screen (and therefore scrolled into view), etc.
  • Rename scroll-snap-padding to scroll-padding to accommodate these changes.

I would propose also to have PageUp/PageDown respond to scroll-padding, since the same concerns apply to it -- the scroll padding area provides control over breathing space and a way for authors to exclude the viewport area beneath overlapping content from what is considered the "visible" area of the scroller.

Key considerations of this proposal:

  • Has no effect on layout or scroll origin.
  • Provides a declarative replacement for a lot of JS scroll-hacking to accommodate UI elements floating over the scrollable area.
  • Solves a longstanding request to control screen overlap for paging / caret-moving operations.

I'm in favor of this proposal.

@ChumpChief

This comment has been minimized.

Copy link
Member

commented Aug 17, 2016

How would this be different from the already-spec'd behavior for proximity snap points? UAs already have the leeway to elect to snap to any given element in these scenarios if appropriate.

The precise model algorithm to select a snap position to snap to is intentionally left mostly undefined, so that user agents can take into account sophisticated models of user intention and interaction and adjust how they respond over time, to best serve the user.

@ChumpChief

This comment has been minimized.

Copy link
Member

commented Aug 17, 2016

This proposal was clarified on the call today, but since more technical discussion was required we agreed to continue the conversation on the issue (here).

The proposal is that even for scroll-snap-type: none, and even for elements with unspecified scroll-snap-margin, the scroll-snap-padding (perhaps renamed) would have some effect on final scroll offsets for a class of scroll operations that bring a particular "thing" into view. That "thing" may not necessarily be an element, e.g. in the case of the caret, so I'll refer to it as the "target" in this post.

As I mentioned on the call, I think this is an interesting problem to consider. But I think it's best to discuss the problem being raised first before getting to implementation details.

Problem

Certain user actions scroll the content with the intent of bringing something "into view". The primary issue that was raised on the call involves content with a fixed element banner/toolbar on the top or bottom. In this case, scrolling the content such that the target is contained within the viewport is necessary but not sufficient -- it may still be obscured by those fixed banners/toolbars. This sucks.

Approaches

To avoid this a UA would need to scroll the content such that the target is not just within the viewport, but also not intersecting with the obscuring content. This brings me to the first solution option: UAs just get smarter about whether the target of the scroll is obscured by something at a given offset when selecting their destination. I haven't thought about this in any detail but on the surface it seems like a solvable problem. I would certainly consider this the most preferable since it wouldn't require work from the author.

But to continue the thought experiment for now let's assume that approach doesn't work -- maybe the UA can't divine enough information about the content without hints from the author. OK, well, common design patterns today involve the banner/toolbar stretching the entire width of the screen, so a simplifying assumption is to assert the "obscuring content" can be adequately described with a simple offset from the top/bottom of the viewport.

A more general approach would be to define the geometry of obscuring elements, but by restricting the feature in this manner we guarantee that the range of scroll offsets that put an element "in view" is contiguous, which is nice. So with those assumptions it does seem that you would need a property that defines the unobscured region which syntactically sounds like a padding. And the UA would need to modify their scrolling logic to account for this padding in some sane way. I think we all agree on that part.

Using scroll-snap-padding specifically

I can understand how scroll-snap-padding was raised as a candidate for this purpose, but adding this additional responsibility to the feature overloads it to the point of damaging both features and introduces many more landmines for authors in the form of unintended side effects:

  • The current semantic of CSS Scroll Snap is around specific alignment of a scroll snap area against the scroll snapport. The candidate feature is not looking for a specific alignment but rather an "acceptable range". This discrepancy is the main root cause of the further issues raised below.
  • Snap positions are defined using both the scroll-snap-padding and scroll-snap-margin. It is not obvious from CSS alone whether scroll-snap-padding is sufficient on its own to define an "acceptable range". E.g. if the author has scroll-snap-padding: 50px; scroll-snap-margin: 50px, then does the "acceptable range" start at 50px or 100px?
  • In a more extreme case, an author might set a negative scroll-snap-padding and rely on a more-positive scroll-snap-margin to bring it back to the desired location. Not saying this would be a recommended practice, but could result in some really nasty behavior if only the scroll-snap-padding was considered.
  • It is not obvious from CSS alone if scroll-snap-padding: 50px; scroll-snap-align: none start; (which only results in snapping in the block axis) should also constrain the target of the scroll in the inline axis or if the author was just careless with shorthand since it didn't impact snapping.
  • It is not obvious from CSS alone if the "acceptable range" for my snapping elements is the same as the "acceptable range" for any other target. E.g. I may want to snap to each page in a document editor with a little breathing room, but not prematurely trigger scrolling if the user clicks to place the caret somewhere within the "breathing room" zone.
  • It is not obvious from CSS alone if scroll-snap-padding should "encourage" aligning the target against the padding, and I think Florian and Elika are saying different things on this point. If you think the padding describes "where in the viewport the focused content should go when scrolling to something on the page in general" as Elika says then it would imply that alignment should be encouraged. Alternatively if you think it should "define the acceptable range of end position from which the UA is free to pick" as Florian says then alignment should not be encouraged.
  • Depending on your opinion for the previous bullet point, it may become more or less important to treat scroll-snap-padding: 0 as a magic number that disengages this behavior, since it is the initial value.
  • The definition of an "acceptable range" assumes that the padding is usually set to match the unobscured region. This may be more likely (but not guaranteed) in the case of scroll-snap-align: none start; or none end, but less so for scroll-snap-align: center. An author may not even care to set the scroll-snap-padding if they use both a top and bottom banner/toolbar since scroll-snap-padding: 100px 0 is effectively the same as scroll-snap-padding: 0 when using scroll-snap-align: center. Or worse, if they have asymmetric toolbars (e.g. 200px top bar, 100px bottom bar) but want to keep the item centered in the viewport, they'll have to sacrifice one of those goals. There would be no way to both accurately describe the obscured region AND keep the element centered in the viewport.
  • It seems likely that authors may neglect to set the scroll-snap-padding on the non-snapping edge of the snapport. If an author has both a top and bottom toolbar, scroll-snap-align: none start and scroll-snap-padding-top: 100px is sufficient to get proper top snapping. Setting scroll-snap-padding-bottom would have no effect on snapping, so they may not realize it's required to ensure the bottom toolbar doesn't obscure the target.
  • scroll-snap-type: none is intended to be the "big off switch" for the feature without requiring the author to additionally reset all of the other properties [1]. If this off switch is not honored in this case, then the author needs to additionally remember to reset the scroll-snap-padding to avoid inappropriate behavior from the half-off state.

[1] https://lists.w3.org/Archives/Public/www-style/2015Mar/0156.html

@fantasai

This comment has been minimized.

Copy link
Collaborator

commented Aug 19, 2016

To respond to your points...

  • This point is, I think, up for debate. For sure if we use scroll-snap-padding, then it should be renamed to scroll-padding to make its purpose clearer. If at some point in the future we think snapping scroll offsets need different values than non-snapping scroll offsets, we can split off sub-properties or have a scroll-snap-padding property whose initial value copies from scroll-padding. Wrt whether scroll-snap-margin should be renamed to scroll-margin and given the same effects... I lean towards no, because it cannot solve some of the problems we're trying to solve here--such as handling carets and pageUp/Dwn, and having a snap-specific offset property is (as you point out in other bullets) useful.
  • Negative padding is a very weird case, and actually points out that we probably should be making negative values for scroll-snap-padding invalid in any case. (Regular padding is not allowed to take negative values either.)
  • I think it's sufficiently clear that scroll-padding applied to the scroller has an effect on all items within it, and does not care about a particular element’s scroll-snap-align value.
  • If an author wants this effect, s/he can use scroll-snap-margin on the element representing the pages.
  • No, I don't think that the padding describes any alignment. It only restricts the geometry of the viewport as it applies to considering an item “in view”. That's it. That is the sum total of the proposed behavior.
  • If the author doesn't use scroll-padding then obviously they don't get the helpful effects of it. Thats consistent with any other property that enhances UA behavior. In cases where there is a desired discrepency between snapping alignment and the scroll-padding values, the scroll-snap-margin properties can be used. Alternatively, if this is a frequently encountered situation, we can have both scroll-padding and scroll-snap-padding as mentioned above.
  • Yes, having to reset scroll-padding to zero is necessary to turn off its effects. However, scroll-snap-type: none will still turn off all scroll snapping behavior, as expected.

To summarize again, the proposal consists of exactly two points:

  • scroll-snap-padding is renamed to scroll-padding
  • scroll-padding reduces the area of the viewport that the UA considers “visible” when performing semantic scrolling operations.

I think it is fairly straightforward, solves a number of additional problems that exist with scrolling, and does not prevent us from providing even finer controls in the future should they be necessary.

@fantasai fantasai added the Agenda+ label Aug 26, 2016

@frivoal frivoal self-assigned this Sep 5, 2016

@ChumpChief

This comment has been minimized.

Copy link
Member

commented Sep 6, 2016

You still seem very focused on the syntax. I can understand why you would associate this new functionality with snapping since both involve "where the scroll goes". However that's where the similarities end I think: snap positions are specifically specified as providing "particular alignments of content within a scroll container" whereas the new proposed functionality doesn't describe any alignment but only a reduced "in view" concept.

In fact, if the feature is primarily designed to provide an "in view" concept, I think it has many further implications unrelated to scrolling. Off the top of my head:

  • An "in view" region would allow for a variety of optimizations in paint and composition, avoiding unnecessary work and memory allocation for non-visible regions.
  • IntersectionObserver's main objective is to provide advertisements with "in view" notification, which could be better informed with this concept.

A feature that unambigously defines an "in view" region could do these things in addition to modifying ScrollIntoView behavior, but to call that feature scroll-padding would be a misnomer. So as I mentioned before I think it's an interesting problem space. I just think you're conflating it with the wrong feature.

@fantasai

This comment has been minimized.

Copy link
Collaborator

commented Sep 7, 2016

Your suggestion of features for an “in view” concept is very different from the one here. It also involves painting, i.e. a
consideration of whether the element is actually visible.

However the “in view“ concept in this proposal is not about whether the element is actually visible, but whether it is
positioned within an optimal section of the viewport. Which is exactly the purpose it currently has in the scroll-snap spec.

@frivoal

This comment has been minimized.

Copy link
Collaborator Author

commented Sep 8, 2016

I have a difficult time understanding how arguments against scroll-padding do no apply equally well against scroll-snap-padding, or inversedly. The motivations for both are exactly the same: in cases where the UA is partly or totally controlling the end scroll position, the author wants to designate an area within the scrollport where it is desirable to place the things that are being scrolled to.

For example, @ChumpChief said:

This brings me to the first solution option: UAs just get smarter about whether the target of the scroll is obscured by something at a given offset when selecting their destination.

Why is this not true for scroll-snap-padding use together with snappoints as well? In both cases, it seems to me that this might be doable in some cases, but is hard in the general case. If you feel this is an area where improvements can realistically be expected, I don't mind adding an auto value to scroll-(snap-)padding. But I don't see why anything that would work for the regular scrolling case wouldn't work just as well for the snapping case.

A more general approach would be to define the geometry of obscuring elements, but by restricting the feature in this manner we guarantee that the range of scroll offsets that put an element "in view" is contiguous.

Again, same question? What about this is different between regular scrolling and snapping? As far as I can tell, scroll-snap-padding does exactly that: it defines a (simplified) geometry of obscuring elements


Whether the UA is scrolling to a certain thing because of proximity snap points, or because of mandatory snap points, or because of navigating to an anchor, or because of focusing a button doesn't make a fundamental different. Regardless of the syntax, we're discussing a property that means "if you're going to scroll to something, put it within there, as long as that doesn't require overscroll".

Taking one single concrete example: let's say you have a long form document, with anchors spread throughout, and proximity snapping on the subsection titles. Say that it also has a semi-transparent reading progress indicator at a fixed position overlapping the top of the scroller, and a semi transparent (that becomes opaque when hovered) dock of social media buttons at a fixed position overlapping the bottom of the scroller. For the sake of the argument, let's say both these things are 20px high.

To avoid subsection titles being snapped at the edge of the scroller where they would be partly obscured by the semi transparent things, you add scroll-snap-padding: 20px 0 (or scroll-snap-padding: 20px, in a vertical scroller the effect will be the same), and now when they snap, they snap in a comfortable place.

In the same document, when the user clicks a link that takes them to a anchor that's not placed on a subsection title, the thing they navigate to will be placed under the semi-transparent progress bar. That makes no sense to me: the author has already told us via scroll-snap-padding that this was not a good place to put things.

I'm certainly open to the idea that I may have overlooked something, but to help me understand what, could you provide a concrete example, in a similar spirit to the one I gave above, which shows a situation where the author sets scroll-snap-padding (as currently specified) in a way that makes sense, but where giving it the additional behavior fantasai and I are arguing for would do something that the user would consider detrimental?

You've mentioned the interaction between scroll-snap-padding and scroll-snap-margin. A simple way to fix this discrepancy would be to apply the same logic to scroll-snap-margin, make it into scroll-margin, and have that apply as well when the UA scrolls to for instance a button that just got focused and that has a scroll-margin.

@atanassov atanassov removed the Agenda+ label Sep 13, 2016

@atanassov

This comment has been minimized.

Copy link
Collaborator

commented Sep 13, 2016

CSSWG Discussion: This topic will be added to the TPAC agenda.

https://lists.w3.org/Archives/Public/www-style/2016Sep/0028.html

@fantasai

This comment has been minimized.

Copy link
Collaborator

commented Sep 26, 2016

This was discussed at TPAC and accepted. The edits are in 0befd3e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.