Skip to content

Commit a64a85b

Browse files
authored
[cssom-view-1] Update spec text for visual viewport scroll and scrollend events (#8205)
Adds normative text for firing the scrollend event on the VisualViewport. scroll was already specified but incorrectly. The text as written meant that a scroll event would have to be dispatched at VisualViewport whenever the document scrolls, even if the VisualViewport didn't scroll. This PR splits the perform a scroll steps into one for scrolling boxes (the existing one) and one for viewports (newly added). The viewport version distributes the scroll between the visual and layout viewports and the uses the scrolling box version to perform the scroll of each. Fixes #8103
1 parent 808ea8e commit a64a85b

File tree

1 file changed

+142
-23
lines changed

1 file changed

+142
-23
lines changed

cssom-view-1/Overview.bs

Lines changed: 142 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,71 @@ does not cause reflow of the page's contents.
278278

279279
The magnitude of the scale transform is known as the <a>visual viewport</a>'s <dfn>scale factor</dfn>.
280280

281+
<style>
282+
@keyframes lvmove {
283+
0%, 10%, 20% { transform: translate(0, 100px); }
284+
30%, 50%, 70% { transform: translate(0, 150px); }
285+
80%,100% { transform: translate(0, 100px); }
286+
}
287+
@keyframes vvmove {
288+
0%, 10% { transform: translate(70px, 150px); }
289+
30%, 50% { transform: translate(70px, 250px); }
290+
80%, 90% { transform: translate(70px, 100px); }
291+
100% { transform: translate(70px, 150px); }
292+
}
293+
#lv {
294+
transform: translate(0, 100px);
295+
animation: lvmove linear 3s infinite;
296+
}
297+
#vv {
298+
transform: translate(20px, 150px);
299+
animation: vvmove linear 3s infinite;
300+
}
301+
.paused #lv {
302+
animation-play-state: paused;
303+
}
304+
.paused #vv {
305+
animation-play-state: paused;
306+
}
307+
</style>
308+
<div class="example paused" id="example-vvanimation">
309+
<p>
310+
This animation shows an example of a zoomed in visual viewport being "panned" around (for
311+
example, by a user performing a touch drag). The page is scaled so that the layout viewport
312+
is larger than the visual viewport.
313+
</p>
314+
<p>
315+
A scroll delta is applied to the visual viewport first. When the visual viewport is at its
316+
extent, scroll delta will be applied to the layout viewport. This behavior is implemented by
317+
the [=viewport/perform a scroll=] steps.
318+
</p>
319+
<svg width="300" height="400">
320+
<rect width="100%" height="100%" fill="white" stroke="grey" stroke-width="3"/>
321+
<text x="10" y="30" font-family="Sans" font-size="25" fill="grey">
322+
Document
323+
</text>
324+
<g id="lv">
325+
<rect y="2" x="2" width="296" height="200" stroke="blue" fill="none" stroke-width="4"/>
326+
<text x="10" y="20" font-family="Sans" font-size="15" fill="blue">
327+
Layout Viewport
328+
</text>
329+
</g>
330+
<g id="vv">
331+
<rect y="2" x="2" width="148" height="100" stroke="red" fill="none" stroke-width="4"/>
332+
<text x="10" y="60" font-family="Sans" font-size="15" fill="red">
333+
Visual Viewport
334+
</text>
335+
</g>
336+
</svg>
337+
<br>
338+
<button id="vvanimationBtn">Toggle Animation</button>
339+
<script>
340+
document.getElementById('vvanimationBtn').onclick = () => {
341+
document.getElementById('example-vvanimation').classList.toggle('paused');
342+
};
343+
</script>
344+
</div>
345+
281346
The {{VisualViewport}} object has an <dfn for=visualviewport>associated document</dfn>, which is a {{Document}} object.
282347
It is the <a for="/">associated document</a> of the owner {{Window}} of {{VisualViewport}}. The <a>layout viewport</a>
283348
is the owner {{Window}}'s <a>viewport</a>.
@@ -363,10 +428,50 @@ the following steps must be run:
363428
Note: <code>behavior: "instant"</code> always performs an <a>instant scroll</a> by this algorithm.
364429

365430
Note: If the scroll position did not change as a result of the user interaction or programmatic invocation, where no translations were applied as a result, then no <a event>scrollend</a> event fires because no scrolling occured.
366-
367-
Note: In the case the VisualViewport was scrolled, yielding no translation changes in the document, emit the <a event>scrollend</a> on the VisualViewport just as the <a event>scroll</a> event is emitted for VisualViewport scrolling.
368431
</ol>
369432

433+
When a user agent is to <dfn for="viewport" export>perform a scroll</dfn> of a <a>viewport</a> to a given position <var>position</var> and optionally a scroll behavior <var>behavior</var>
434+
(which is "<code>auto</code>" if omitted) it must perform a coordinated viewport scroll by following these steps:
435+
436+
1. Let <var>doc</var> be the <a>viewport's</a> associated {{Document}}.
437+
1. Let <var>vv</var> be the {{VisualViewport}} whose <a for=visualviewport>associated document</a> is <var>doc</var>.
438+
1. Let <var>maxX</var> be the difference between <a>viewport</a>'s <a>scrolling box</a>'s width and the value of <var>vv</var>'s <a attribute
439+
for=VisualViewport lt=width>width</a> attribute.
440+
1. Let <var>maxY</var> be the difference between <a>viewport</a>'s <a>scrolling box</a>'s height and the value of <var>vv</var>'s <a attribute
441+
for=VisualViewport lt=height>height</a> attribute.
442+
1. Let <var>dx</var> be the horizontal component of <var>position</var> - the value <var>vv</var>'s <a attribute for=VisualViewport lt=pageLeft>pageLeft</a> attribute
443+
1. Let <var>dy</var> be the vertical component of <var>position</var> - the value of <var>vv</var>'s <a attribute for=VisualViewport lt=pageTop>pageTop</a> attribute
444+
1. Let <var>visual x</var> be the value of <var>vv</var>'s <a attribute for=VisualViewport lt=offsetLeft>offsetLeft</a> attribute.
445+
1. Let <var>visual y</var> be the value of <var>vv</var>'s <a attribute for=VisualViewport lt=offsetTop>offsetTop</a> attribute.
446+
1. Let <var>visual dx</var> be min(<var>maxX</var>, max(0, <var>visual x</var> + <var>dx</var>)) - <var>visual x</var>.
447+
1. Let <var>visual dy</var> be min(<var>maxY</var>, max(0, <var>visual y</var> + <var>dy</var>)) - <var>visual y</var>.
448+
1. Let <var>layout dx</var> be <var>dx</var> - <var>visual dx</var>
449+
1. Let <var>layout dy</var> be <var>dy</var> - <var>visual dy</var>
450+
1. Let <var>element</var> be <var>doc</var>'s root element if there is one, null otherwise.
451+
1. <a for="/">Perform a scroll</a> of the <a>viewport</a>'s <a>scrolling box</a> to its current scroll position + (<var>layout dx</var>, <var>layout dy</var>) with <var>element</var> as the
452+
associated element, and <var>behavior</var> as the scroll behavior.
453+
1. <a for="/">Perform a scroll</a> of <var>vv</var>'s <a>scrolling box</a> to its current scroll position + (<var>visual dx</var>, <var>visual dy</var>) with <var>element</var> as the associated
454+
element, and <var>behavior</var> as the scroll behavior.
455+
456+
Note: Conceptually, the visual viewport is scrolled until it "bumps up" against the layout viewport
457+
edge and then "pushes" the layout viewport by applying the scroll delta to the layout viewport.
458+
However, the scrolls in the steps above are computed ahead of time and applied in the opposite order
459+
so that the layout viewport is scrolled before the visual viewport. This is done for historical
460+
reasons to ensure consistent scroll event ordering. See the <a href="#example-vvanimation">example
461+
above</a> for a visual depiction.
462+
463+
<div class='example'>
464+
The user pinch-zooms into the document and ticks their mouse wheel, requesting the user agent scroll the document down by 50px. Because the document
465+
is pinch-zoomed in, the visual viewport has 20px of room to scroll. The user agent distributes the scroll by scrolling the visual viewport down by
466+
20px and the layout viewport by 30px.
467+
</div>
468+
469+
<div class='example'>
470+
The user is viewing a document in a mobile user agent. The document focuses an offscreen text input element, showing a virtual keyboard which shrinks
471+
the visual viewport. The user agent must now bring the element into view in the visual viewport. The user agent scrolls the layout viewport so that
472+
the element is visible within it, then the visual viewport so that the element is visible to the user.
473+
</div>
474+
370475
Scroll is <dfn lt="scroll completed">completed</dfn> when the scroll position has no more pending updates or translations and the user has completed their gesture. Scroll position updates include smooth or instant mouse wheel scrolling, keyboard scrolling, scroll-snap events, or other APIs and gestures which cause the scroll position to update and possibly interpolate. User gestures like touch panning or trackpad scrolling aren't complete until pointers or keys have released.
371476

372477
When a user agent is to perform a <dfn export id=concept-smooth-scroll>smooth scroll</dfn> of a <a>scrolling box</a> <var>box</var> to <var>position</var>,
@@ -386,7 +491,7 @@ To <dfn export>scroll to the beginning of the document</dfn> for a document <var
386491
<a>scrolling area</a> with the <a>beginning edges</a> of <var>viewport</var>.
387492
<li>If <var>position</var> is the same as <var>viewport</var>'s current scroll position, and <var>viewport</var> does not have an ongoing
388493
<a>smooth scroll</a>, abort these steps.
389-
<li><a>Perform a scroll</a> of <var>viewport</var> to <var>position</var>,
494+
<li><a for="viewport">Perform a scroll</a> of <var>viewport</var> to <var>position</var>,
390495
and <var>document</var>'s [=root element=] as the associated element, if there is one, or null otherwise.
391496
</ol>
392497

@@ -579,10 +684,13 @@ steps must be run:
579684
1. If <var>position</var> is the same as the <a>viewport’s</a> current scroll position,
580685
and the <a>viewport</a> does not have an ongoing <a>smooth scroll</a>, abort these steps.
581686
1. Let <var>document</var> be the <a>viewport’s</a> associated {{Document}}.
582-
1. <a>Perform a scroll</a> of the <a>viewport</a> to <var>position</var>,
687+
1. <a for="viewport">Perform a scroll</a> of the <a>viewport</a> to <var>position</var>,
583688
<var>document</var>'s [=root element=] as the associated element, if there is one, or null otherwise,
584689
and the scroll behavior being the value of the {{ScrollOptions/behavior}} dictionary member of <var>options</var>.
585690

691+
Issue: User agents do not agree whether this uses the (coordinated) <a>viewport</a> <a for="viewport">perform a scroll</a> or the
692+
<a>scrolling box</a> <a for="/">perform a scroll</a> on the layout viewport's scrolling box.
693+
586694
When the <dfn method for=Window lt="scrollTo(options)|scrollTo(x, y)">scrollTo()</dfn> method is invoked, the
587695
user agent must act as if the {{Window/scroll()}} method was invoked with the same arguments.
588696

@@ -1371,14 +1479,15 @@ a <a>scrolling box</a> <var>scrolling box</var>, in order of innermost to outerm
13711479
1. <dl class=switch>
13721480
<dt>If <var>scrolling box</var> is associated with an element
13731481
<dd>
1374-
Let <var>associated element</var> be the element.
1375-
1482+
<a for="/">Perform a scroll</a> of the element's <var>scrolling box</var> to <var>position</var>, with the element as the associated element and
1483+
<var>behavior</var> as the scroll behavior.
13761484
<dt>If <var>scrolling box</var> is associated with a <a>viewport</a>
13771485
<dd>
1378-
Let <var>document</var> be the <a>viewport’s</a> associated {{Document}}.
1379-
Let <var>associated element</var> be <var>document</var>'s [=root element=], if there is one, or null otherwise.
1486+
1. Let <var>document</var> be the <a>viewport’s</a> associated {{Document}}.
1487+
1. Let <var>root element</var> be <var>document</var>'s [=root element=], if there is one, or null otherwise.
1488+
1. <a for="viewport">Perform a scroll</a> of the <a>viewport</a> to <var>position</var>, with <var>root element</var> as the associated element and <var>behavior</var>
1489+
as the scroll behavior.
13801490
</dl>
1381-
1. <a>Perform a scroll</a> of <var>scrolling box</var> to <var>position</var>, <var>associated element</var> as the associated element and <var>behavior</var> as the scroll behavior.
13821491

13831492

13841493
To <dfn>scroll an element</dfn> <var>element</var> to <var>x</var>,<var>y</var> optionally with a scroll behavior <var>behavior</var> (which is "<code>auto</code>" if omitted) means to:
@@ -1400,7 +1509,7 @@ To <dfn>scroll an element</dfn> <var>element</var> to <var>x</var>,<var>y</var>
14001509
</dl>
14011510
1. Let <var>position</var> be the scroll position <var>box</var> would have by aligning <a>scrolling area</a> x-coordinate <var>x</var> with the left of <var>box</var> and aligning <a>scrolling area</a> y-coordinate <var>y</var> with the top of <var>box</var>.
14021511
1. If <var>position</var> is the same as <var>box</var>'s current scroll position, and <var>box</var> does not have an ongoing <a>smooth scroll</a>, abort these steps.
1403-
1. <a>Perform a scroll</a> of <var>box</var> to <var>position</var>, <var>element</var> as the associated element and <var>behavior</var> as the scroll behavior.
1512+
1. <a for="/">Perform a scroll</a> of <var>box</var> to <var>position</var>, <var>element</var> as the associated element and <var>behavior</var> as the scroll behavior.
14041513

14051514

14061515

@@ -1793,24 +1902,33 @@ Whenever an element gets scrolled (whether in response to user interaction or by
17931902
1. If the element is already in <var>doc</var>'s <a>pending scroll event targets</a>, abort these steps.
17941903
1. Append the element to <var>doc</var>'s <a>pending scroll event targets</a>.
17951904

1905+
Whenever a <a>visual viewport</a> gets scrolled (whether in response to user interaction or by an API), the user agent must run these steps:
1906+
1907+
1. Let <var>vv</var> be the {{VisualViewport}} object that was scrolled.
1908+
1. Let <var>doc</var> be <var>vv</var>'s <a for=visualviewport>associated document</a>.
1909+
1. If <var>vv</var> is already in <var>doc</var>'s <a>pending scroll event targets</a>, abort these steps.
1910+
1. Append <var>vv</var> to <var>doc</var>'s <a>pending scroll event targets</a>.
1911+
17961912
When asked to <dfn export for=Document>run the scroll steps</dfn> for a {{Document}} <var>doc</var>, run these steps:
17971913

17981914
1. For each item <var>target</var> in <var>doc</var>'s <a>pending scroll event targets</a>,
17991915
in the order they were added to the list, run these substeps:
18001916

1801-
1. If <var>target</var> is a {{Document}}, <a>fire an event</a> named <a event>scroll</a> that bubbles at <var>target</var> and <a>fire an event</a>
1802-
named <a event>scroll</a> at the {{VisualViewport}} that is associated with <var>target</var>.
1917+
1. If <var>target</var> is a {{Document}}, <a>fire an event</a> named <a event>scroll</a> that bubbles at <var>target</var>.
18031918
1. Otherwise, <a>fire an event</a> named <a event>scroll</a> at <var>target</var>.
18041919
1. Empty <var>doc</var>'s <a>pending scroll event targets</a>.
18051920

18061921
Whenever scrolling is <a lt="scroll completed">completed</a>, the user agent must run these steps:
18071922

1808-
1. If scrolling was done on a <a>viewport</a>, let <var>doc</var> be the <a>viewport’s</a> associated {{Document}} and <var>target</var> be the <a>viewport</a>.
1809-
Otherwise, scrolling is done on an element and let <var>doc</var> be the element's <a>node document</a> and <var>target</var> be the element.
1810-
1. If <var>target</var> is already in <var>doc</var>'s <a>pending scrollend event targets</a>, abort these steps.
1811-
1. Append <var>target</var> to <var>doc</var>'s <a>pending scrollend event targets</a>.
1812-
1. For each item <var>target</var> in <var>doc</var>'s <a>pending scrollend event targets</a>, in the order they were added to the list, run these substeps:
1923+
Issue: In what order are scrollend events dispatched? Ordered based on scroll start or scroll completion?
18131924

1925+
1. For each scrolling box <var>box</var> that was scrolled:
1926+
1. If <var>box</var> belongs to a <a>viewport</a>, let <var>doc</var> be the <a>viewport’s</a> associated {{Document}} and <var>target</var> be the <a>viewport</a>.
1927+
If <var>box</var> belongs to a {{VisualViewport}}, let <var>doc</var> be the {{VisualViewport}}'s <a for=visualviewport>associated document</a> and <var>target</var>
1928+
be the {{VisualViewport}}. Otherwise, <var>box</var> belongs to an element and let <var>doc</var> be the element's <a>node document</a> and <var>target</var> be the element.
1929+
1. If <var>target</var> is already in <var>doc</var>'s <a>pending scrollend event targets</a>, abort these steps.
1930+
1. Append <var>target</var> to <var>doc</var>'s <a>pending scrollend event targets</a>.
1931+
1. For each item <var>target</var> in <var>doc</var>'s <a>pending scrollend event targets</a>, in the order they were added to the list, run these substeps:
18141932
1. If <var>target</var> is a {{Document}}, <a>fire an event</a> named <a event>scrollend</a> that bubbles at <var>target</var>.
18151933
1. Otherwise, <a>fire an event</a> named <a event>scrollend</a> at <var>target</var>.
18161934
1. Empty <var>doc</var>'s <a>pending scrollend event targets</a>.
@@ -1836,14 +1954,15 @@ Whenever scrolling is <a lt="scroll completed">completed</a>, the user agent mus
18361954
<tr>
18371955
<td><dfn event for="Document, Element, VisualViewport">scroll</dfn>
18381956
<td>{{Event}}
1839-
<td>{{Document}}, elements, {{VisualViewport}}
1840-
<td>Fired at the {{Document}} or element when the <a>viewport</a> or element is scrolled, respectively. Fired at the {{VisualViewport}}
1841-
when the <a>visual viewport</a> is scrolled.
1957+
<td>{{VisualViewport}}, {{Document}}, elements
1958+
<td>Fired at the {{VisualViewport}}, {{Document}} or element when the {{VisualViewport}}, <a>viewport</a>, or element is scrolled, respectively.
18421959
<tr>
1843-
<td><dfn event for="Document, Element">scrollend</dfn>
1960+
<td><dfn event for="Document, Element, VisualViewport">scrollend</dfn>
18441961
<td>{{Event}}
1845-
<td>{{Document}}, elements
1846-
<td>Fired at the {{Document}} or element when scroll is <a lt="scroll completed">completed</a>: the <a>viewport</a> or element has been scrolled, the scroll sequence has ended and any scroll offset changes have been applied.
1962+
<td>{{Document}}, elements, {{VisualViewport}}
1963+
<td>Fired at the {{VisualViewport}}, {{Document}}, or element when a scroll is <a lt="scroll completed">completed</a>: the
1964+
{{VisualViewport}}, <a>viewport</a>, or element has been scrolled, the scroll sequence has ended and any scroll offset changes have
1965+
been applied.
18471966
</table>
18481967

18491968

0 commit comments

Comments
 (0)