-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Add initial scroll position hook to HTML spec #10759
base: main
Are you sure you want to change the base?
Conversation
scroll-start-target is a CSS property which affects an element's initial scroll position. A scroll container's initial scroll position determines what scroll offset that scroll container should be at before any "explicit" scrolling (e.g. user gesture, programmatic scroll API) occurs on it. This initial scroll position is affected by CSS properties such as scroll-start-target and might change as a document is loaded. This patch adds a step in the "Updating the document" section of the HTML spec to direct user agents on when to re-evaluate initial scroll positions and adjust accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dbaron would you be willing to review this as well?
source
Outdated
<p>To <dfn>update the initial scroll positions for scroll containers</dfn> in a | ||
<code>Document</code> <var>document</var>, | ||
perform the following steps:</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation here doesn't follow the contribution guidelines. (This also applies elsewhere in this PR it seems.) You can also leave out "perform the following steps" here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I believe I've now fixed the indentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I worry about where this integrates into the page lifecycle. It's in "update document for history step application", and occurs in both documentIsNew = true and false cases.
This means:
-
It will run for bfcache traversals. This is probably not correct; bfcache traversals should probably just leave the document as it was, instead of performing extra scroll adjustments.
-
For new documents, it will run before most of the document content is loaded. This is probably not correct; documents will generally have no scroll containers at this early stage of the process.
Can I ask how you are implementing this in Chromium, and in particular, at what point in the document lifecycle? Do you do so immediately (like this spec), and just ignore the fact that there probably will be no scrollers at this early point? Do you wait for the load
or DOMContentLoaded
events? Do you do periodic polling and retrying, like the spec's current "try to scroll to the fragment"?
Step should happen within "If documentIsNew" block like fragment-scroll.
672d3da
to
ae81ba7
Compare
I think you're right that the placement of the step is not correct. I ought to have placed the step within the "If documentIsNew is true" block, and I've done so now. The intent is for it to have similar timing to (but lower priority than) "try to scroll to the fragment" so that user agents treat late-arriving scroll containers and/or their |
The issue is that "try to scroll to the fragment" does a periodic polling operation, which your spec does not. Your spec only tries once, at initial document load, at which point no scrollers will exist. Again, can I ask how you implemented this in Chromium? |
Ah thanks, that's clear to me now.
The implementation in Chromium does periodically poll like you asked. I guess the hook I'm adding should follow a similar pattern to "try to scroll to the fragment"?
Let me know if this sounds reasonable or there's a totally different better approach, thanks! |
That strategy does sound reasonable, although I wonder if you should merge the algorithm with "try to scroll to the fragment" so that they're not competing with each other. Again, I wonder what you do in Chromium; do you have two separate periodic polling algorithms running, one for fragment and one for scroll containers? Or just one? |
In Chromium we poll separately for scrolling to the fragment and scroll containers. And we treat scrolling to the fragment as an "explicit scroll" (like a scroll gesture) as a way of giving it precedence over initial-scroll-position-affecting properties like |
There might be no scroll containers the first time the algorithm runs, so we need to keep polling until the user agent believes the user is no longer interested in the initial scroll position.
<li><p><span data-x="perform a scroll">Perform a scroll</span> of <var>scroller</var>'s <span | ||
data-x="scrolling box">scrolling box</span> to <var>position</var>.</p></li> | ||
|
||
<li><p><span>Update the initial scroll position</span> for <var>scroller</var>.</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This always calls itself recursively. That doesn't seem right... it seems like the first time you succeed, you should stop looping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for calling this out. The idea is for user agents to keep scrollers scrolled to their initial scroll position until some user action indicates otherwise. Since style properties can change the initial scroll position, we need to keep re-evaluating the initial scroll position until such a user action has taken place. I think that, in practice, this re-evaluating of the initial scroll position will simply lead to a noop most of the time.
Also, this is pretty much what user agents should already do with properties like align-content. You can see in this demo (which, unfortunately, only works in Safari at the moment) that as messages are loaded, the scroll position needs to be updated to keep the first message scrolled to, which is what align-content: end
is used for here. As soon as the user scrolls, the scroll container is no longer kept at the initial scroll position.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. So this is fairly different from the "try to scroll to a fragment" case, where we continue until the fragment is loaded; instead, we need to actively continue, possibly forever. Very interesting!
Let's summarize this in a <p class="note">
after "update the initial scroll position". Something like:
Although [try to scroll to the fragment] and [update the initial scroll position for scroll containers] take place at the same point, and both use a polling system to periodically re-attempt the scrolling, their goals are different. [Try to scroll to the fragment] polls repeatedly until the [indicated part] of the document is found, since it may take a while for the element to show up during the document load. [Update the initial scroll positions for scroll containers] does not have such a finish condition; it can run indefinitely, as long as the user does not indicate disinterest. This is necessary to achieve the desired behavior of keeping a [scroll container] "snapped" to the position indicated by certain CSS properties.
Please feel free to improve my wording; that's just my best understanding so far!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I think your note summarizes it quite well, Done.
A few improvements.
<li><p><span data-x="perform a scroll">Perform a scroll</span> of <var>scroller</var>'s <span | ||
data-x="scrolling box">scrolling box</span> to <var>position</var>.</p></li> | ||
|
||
<li><p><span>Update the initial scroll position</span> for <var>scroller</var>.</p></li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. So this is fairly different from the "try to scroll to a fragment" case, where we continue until the fragment is loaded; instead, we need to actively continue, possibly forever. Very interesting!
Let's summarize this in a <p class="note">
after "update the initial scroll position". Something like:
Although [try to scroll to the fragment] and [update the initial scroll position for scroll containers] take place at the same point, and both use a polling system to periodically re-attempt the scrolling, their goals are different. [Try to scroll to the fragment] polls repeatedly until the [indicated part] of the document is found, since it may take a while for the element to show up during the document load. [Update the initial scroll positions for scroll containers] does not have such a finish condition; it can run indefinitely, as long as the user does not indicate disinterest. This is necessary to achieve the desired behavior of keeping a [scroll container] "snapped" to the position indicated by certain CSS properties.
Please feel free to improve my wording; that's just my best understanding so far!
The search for scroll containers includes shadow trees, so the list traversal order should account for shadow trees. Adds a note to clarify the recursive nature of "update initial scroll positions for scroll containers" as it differs from "try to scroll to the fragment."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. We can merge after all the checkboxes in the OP are filled out.
Can you be sure that the following are tested in the web platform tests?
- That scrollers inside shadow trees are included
- That the order is shadow-including tree order, not e.g. flat tree order
scroll-start-target is a CSS property which affects an element's initial scroll position. A scroll container's initial scroll position determines what scroll offset that scroll container should be at before any "explicit" scrolling (e.g. user gesture, programmatic scroll API) occurs on it. This initial scroll position is affected by CSS properties such as scroll-start-target and might change as a document is loaded.
This patch adds a step in the "Updating the document" section of the HTML spec to direct user agents on when to re-evaluate initial scroll positions and adjust accordingly.
(See WHATWG Working Mode: Changes for more details.)
/acknowledgements.html ( diff )
/browsing-the-web.html ( diff )
/infrastructure.html ( diff )