Skip to content

Commit f6c5aaf

Browse files
committed
[scroll-animations-1] minor cleanups to EXPLAINER (#4913)
1 parent 3b5ed09 commit f6c5aaf

File tree

1 file changed

+83
-70
lines changed

1 file changed

+83
-70
lines changed

scroll-animations-1/EXPLAINER.md

Lines changed: 83 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11

22
# Scroll-linked Animations Explainer
33

4-
Note: This document follows the [w3ctag best-practice](https://w3ctag.github.io/explainers) for explainers.
4+
Note: This document follows the [w3ctag best-practice](https://w3ctag.github.io/explainers) for
5+
explainers.
56

67
## Participate
78
[Issue tracker](https://github.com/w3c/csswg-drafts/labels/scroll-animations)
@@ -11,12 +12,12 @@ Note: This document follows the [w3ctag best-practice](https://w3ctag.github.io/
1112
Scroll-linked animations are a common UX pattern on the web. We are proposing a new API that works
1213
in conjunction with existing [Web Animations](https://drafts.csswg.org/web-animations/) and [CSS
1314
Animations](https://drafts.csswg.org/css-animations/) APIs to enable declarative scroll-linked
14-
animations improving their smoothness and ergonomics. In Web Animations, an
15+
animations to improve their smoothness and ergonomics. In Web Animations, an
1516
[AnimationTimeline](https://drafts.csswg.org/web-animations/#timelines) is the source of time
1617
progress that drives the animations. ScrollTimeline is a new timeline whose function is to
1718
translate “changes in scroll position” of an element into “changes in time”. This allows animations
1819
to be driven by scrolling as opposed to by wall clock thus taking advantage of all existing
19-
animation machinery in the web.
20+
animation machinery on the web.
2021

2122
## Motivating Use Cases and Goals
2223

@@ -25,22 +26,24 @@ Scroll-linked animated effect are common in web design:
2526
* Reveal/Unreveal effects
2627
* Image Zoom effects
2728
* Progress-bar animations
28-
* Before/After panoramas
29+
* Scroll-driven Before/After Image slider
2930
* Creative scroll-driven story-telling
3031

3132

32-
Currently the only way to achieve them is to respond to scroll events in the main thread. This
33-
means that these animations have to run on the main thread. There are two main problems to this:
34-
Modern browsers perform scrolling on separate thread/process so scroll events are delivered
35-
asynchronously Main thread animations are subject to jank. Creating performant scroll-linked
36-
animation can be impossible or [very
33+
Currently the only way to achieve them is to respond to scroll events on the main thread. This
34+
means that these animations have to run on the main thread. There are two main problems with this:
35+
1. Modern browsers perform scrolling on separate thread/process so scroll events are delivered
36+
asynchronously
37+
2. Main thread animations are subject to jank.
38+
39+
Creating performant scroll-linked animation can be impossible or [very
3740
difficult](https://developers.google.com/web/updates/2016/12/performant-parallaxing).
3841

3942

4043
Our primary goal is to enable declarative scroll-linked animations that can be easily moved off
41-
thread similar to existing time-based web animations. Our secondary goal is to bring scroll-linked
42-
animation under the existing common web-animation model allowing them to be created, inspected,
43-
controlled via a common animations API.
44+
main thread similar to existing time-based web animations. Our secondary goal is to bring
45+
scroll-linked animation under the existing common web-animation model allowing them to be created,
46+
inspected, controlled via a common animations API.
4447

4548
### Non-goals
4649
* **Scroll-triggered animations**: these are time-based animations that may be triggered when a
@@ -52,8 +55,8 @@ controlled via a common animations API.
5255
ScrollTimeline proposal does not prohibit.
5356

5457
* **Stateful scripted scroll driven animations**: Some scroll-linked animations may not fit well
55-
within declarative animations (e.g., those that depend on scroll velocity, or direction, or have
56-
custom per frame logic etc.). We believe these can continue to be solved using rAF (and in future
58+
within declarative animations such as those that depend on scroll velocity, or direction, or have
59+
custom per frame logic. We believe these can continue to be solved using rAF (and in future
5760
be made more efficient with [CSS Animation
5861
Worklet](https://drafts.css-houdini.org/css-animationworklet/)). ScrollTimeline may be used in
5962
conjunction with these.
@@ -120,11 +123,11 @@ A ScrollTimeline is specified by a number of parameters:
120123

121124
#### CSS syntax
122125

123-
We are introducing a new @timline rule similar to existing @keyframes rule. This will allow
126+
We are introducing a new `@timeline` rule similar to the existing `@keyframes` rule. This will allow
124127
scroll-linked animation to be specified in CSS.
125128

126-
Here is a simple example to demonstrate this which fades the target as `#scroller` scroll from
127-
0 to max.
129+
Here is an example to demonstrate this which fades the target as `#scroller` scroll from zero to
130+
max.
128131

129132
```css
130133
#target {
@@ -214,11 +217,11 @@ const scroller = document.getElementById("scroller");
214217
const image = document.getElementById("image");
215218

216219
const revealTimeline = new ScrollTimeline({
217-
// timeline starts at the offset that corresponds with image starting
220+
// Timeline starts at the offset that corresponds with image starting
218221
// to enter scrollport (i.e., 0% intersect with scroller at itsendedge).
219222
start: { target: image, edge: 'end', threshold: 0 },
220223

221-
// timeline ends at the offset that corresponds with image becoming
224+
// Timeline ends at the offset that corresponds with image becoming
222225
// fully visible (i.e., 100% intersect with scroller at its “end” edge).
223226
end: { target: image, edge: 'end', threshold: 1 },
224227
});
@@ -243,10 +246,10 @@ polyfill](https://flackr.github.io/scroll-timeline/demo/parallax/index.html).
243246
### Scenario 1 - Parallax
244247

245248

246-
Parallax is a most popular scroll-linked effects on the web today. See Android 10 launch
249+
Parallax is one of the most popular scroll-linked effects on the web today. See Android 10 launch
247250
[site](https://www.android.com/android-10/) for an example of this.
248251

249-
![Parallax example](https://gist.github.com/majido/a1279d6d986ab8881d51a77e98769e69/raw/307c1f83367c59a1c0d15f9f696fa483daaf828b/explainer-parallax.gif)
252+
![Parallax example](https://gist.github.com/majido/a1279d6d986ab8881d51a77e98769e69/raw/explainer-parallax.gif)
250253

251254
To create a parallax effect with ScrollTimeline APIs, one can simply do:
252255

@@ -270,7 +273,7 @@ often used to create interactive stories. For example see how New York Times app
270273
animations for creative
271274
[storytelling](http://www.nytimes.com/projects/2013/tomato-can-blues/index.html).
272275

273-
![Reveal example](https://gist.github.com/majido/a1279d6d986ab8881d51a77e98769e69/raw/307c1f83367c59a1c0d15f9f696fa483daaf828b/explainer-reveal.gif)
276+
![Reveal example](https://gist.github.com/majido/a1279d6d986ab8881d51a77e98769e69/raw/explainer-reveal.gif)
274277

275278

276279
Here is a simple example where we reveal each header as they enters the viewport. This example uses
@@ -324,7 +327,7 @@ document.querySelector('#progressbar').animate({
324327
This is another common usage pattern when an image scales up to fill a larger canvas. For an
325328
example of this see [iPhone 11 launch site](https://www.apple.com/iphone-11/).
326329
327-
![Zoom example](https://gist.github.com/majido/a1279d6d986ab8881d51a77e98769e69/raw/307c1f83367c59a1c0d15f9f696fa483daaf828b/explainer-zoom.gif)
330+
![Zoom example](https://gist.github.com/majido/a1279d6d986ab8881d51a77e98769e69/raw/explainer-zoom.gif)
328331
329332
In this example we start scaling a DIV as soon as its container fully enters the scrollport and
330333
until it starts existing the scroll port. Not how in this case the animating element is different
@@ -365,12 +368,13 @@ Some of the complexities that come from this decision are:
365368
addresses this issue among other benefits.
366369
367370
* **Exclusive end ranges**: In Web Animations, ranges have exclusive ends to
368-
help make it easier to use overlapping ranges (e.g., putting animations in a
369-
sequence). ScrollTimeline scroll range also has exclusive ends to match this.
370-
However this is problematic for a common case where scroll range is full size.
371-
Our solution was to [special case](https://github.com/w3c/csswg-drafts/issues/4341) this one.
371+
help make it easier to use overlapping ranges such as putting multiple
372+
animations in a sequence. ScrollTimeline scroll range also has exclusive ends
373+
to match this. However this is problematic for a common case where scroll
374+
range is full size. Our solution was to [special
375+
case](https://github.com/w3c/csswg-drafts/issues/4341) this one.
372376
373-
* **Dynamic Scrollability**: It is possible for an scroller to no longer
377+
* **Dynamic Scrollability**: It is possible for a scroller to no longer
374378
overflow (`overflow: auto`). It is not clear how best to model this behavior.
375379
One option is to model this as an idle timeline. One current limitation of web
376380
animation is that when a timeline goes from playing to idle, its attached
@@ -383,61 +387,70 @@ The ability for scrolling to drive the progress of an animation, gives rise to t
383387
layout cycles, where a change to a scroll offset causes an animation’s effect to update, which in
384388
turn causes a new change to the scroll offset. Imagine that an animation shrinks the height of the
385389
content of the scroller which may cause the max scroll offset to reduce which may change the scroll
386-
offset. To avoid such layout cycles, animations with a ScrollTimeline are sampled once per frame,
387-
after scrolling in response to input events has taken place, but before `requestAnimationFrame()`
390+
offset.
391+
392+
393+
To avoid such layout cycles, animations with a ScrollTimeline are sampled once per frame, after
394+
scrolling in response to input events has taken place, but before `requestAnimationFrame()`
388395
callbacks are run. If the sampling of such an animation causes a change to a scroll offset, the
389396
animation will not be re-sampled to reflect the new offset until the next frame.
390397
391398
![Ordering of scroll-linked animations](img/explainer-ordering.svg)
392399
393-
Note that this ensures the output of scroll-linked animation is always up-to-date when
394-
the user is scrolling and avoids layout cycle. But it also means that in some situations the
395-
rendered scroll offset may not be consistent with the output of scroll-driven animations for
396-
example when the scroll-linked animation is indirectly changing the scroll offset itself. We
397-
believe this is rare and often not actually desired by authors. Another thing to note is that if
398-
one updates scroll offsets in requestAnimationFrame it is not reflected in scroll-linked animations
399-
in the same frame. This is because rAF are specced to run after updating web animations which
400-
includes scroll-linked animations.
400+
Note that this ensures the output of scroll-linked animation is always up-to-date when the user is
401+
scrolling and avoids layout cycle. But it also means that in some situations the rendered scroll
402+
offset may not be consistent with the output of scroll-driven animations. For example when the
403+
scroll-linked animation itself is indirectly causing the scroll offset to change. We believe this
404+
is rare and often not actually desired by authors.
405+
401406
407+
Another thing to note is that if one updates scroll offsets in a `requestAnimationFrame` callback
408+
it is not reflected in scroll-linked animations in the same frame. This is because
409+
`requestAnimationFrame` callback are specified to run after updating web animations step which includes
410+
scroll-linked animations.
402411
403412
### Accommodate Asynchronous Scrolling
404-
Most modern browsers perform scrolling asynchronous (i.e. off main-thread). We have opted for the
405-
following model to ensure that is not affected:
413+
414+
Most modern browsers [perform scrolling
415+
asynchronously](https://blogs.windows.com/msedgedev/2017/03/08/scrolling-on-the-web/) to ensure
416+
smoothness and responsiveness to user actions. In other words the majority of scrolling is handled
417+
off main-thread. We have opted for the following model to ensure that is not affected:
418+
406419
1. The scroll-linked effects are expressed declaratively similar to other
407420
web-animations and may be sampled asynchronously.
408-
2. User-agent is allowed to sample scroll-linked animations more often than main
409-
thread animation frames. These two mean that scroll-linked animation can
410-
potentially run off-main thread and in sync with asynchronous scrolling that
411-
happens off thread.
412-
3. User-agent is allowed to sample the scroll-linked effects on main-thread once
421+
2. The user-agent is allowed to sample scroll-linked animations more often than main
422+
thread animation frames.
423+
3. The user-agent is allowed to sample the scroll-linked effects on main-thread once
413424
per main-thread animation frame and use the last known scroll offset.
414425
415-
The above give a minimum guarantee that scroll-linked animations would render as
416-
often as the current existing approach of using scroll events while also
417-
enabling user-agents to optimize such animations to potentially run off-thread
418-
and more in sync with asynchronous scrolling.
426+
427+
(1) and (2) mean that scroll-linked animation can potentially run off-main thread and in sync with
428+
asynchronous scrolling that happens off thread. (3) ensures they can also run on main-thread
429+
without forcing scrolling itself to be on main thread. Together they guarantee that scroll-linked
430+
animations would render as often as the current existing approach of using scroll events while also
431+
enabling user-agents to optimize such animations to potentially run off-thread and in sync with
432+
asynchronous scrolling.
419433
420434
### Progress-Based Animations
421435
422-
As mentioned before we like to eliminate the need for `ScrollTimeline.timeRange`
423-
to map scroll units into time units. One approach we are exploring is the
424-
addition of progress-based animations to Web Animations. This will allow the
425-
scroll timeline to produce a “progress” value which can drive animations without
426-
a need for durations. Progress-based animations will have other value beside
427-
scroll linked-animations. This is a work-in-progress and there is an ongoing
428-
discussion around it [here](https://github.com/w3c/csswg-drafts/issues/4862).
436+
As mentioned before we like to eliminate the need for `ScrollTimeline.timeRange` to map scroll
437+
units into time units. One approach we are exploring is the addition of progress-based animations
438+
to Web Animations. This will allow the scroll timeline to produce a “progress” value which can
439+
drive animations without a need for durations. Progress-based animations will have other value
440+
beside scroll linked-animations. This is a work-in-progress and there is an ongoing discussion
441+
around it [here](https://github.com/w3c/csswg-drafts/issues/4862).
429442
430443
### Access top-level window scroll in iframes
431444
432445
It is desirable to perhaps allow scroll-linked animations to respond to the top-level window
433-
viewport in . The current specification does not allow this as we are not sure of the security
434-
impact of enabling this in cross-origin iframes. But in terms of API it may be just as simple of
435-
allowing empty source attributes to mean top-level window scroller. More discussion on the usecase
436-
and possible solutions are [here](https://github.com/w3c/csswg-drafts/issues/4344)
446+
viewport in an iframe. The current specification does not allow this as we are not sure of the
447+
security impact of enabling this in cross-origin iframes. But in terms of API it may be just as
448+
simple of allowing empty source attributes to mean top-level window scroller. More discussion on
449+
the use case and possible solutions are [here](https://github.com/w3c/csswg-drafts/issues/4344)
437450
438451
### Logical Scrolling vs Animation of Physical properties
439452
440-
This is not an issue directly related to Scroll-Linked animation but one that gets exposed more
453+
This is not an issue directly related to Scroll-linked animation but one that gets exposed more
441454
clearly with it. The issue is that many CSS properties, most predominantly transform, are physical
442455
but ScrollTimeline orientation is logical in that it can be affected by writing-mode). So authors
443456
have to be careful to use physical orientation with a scroll timeline if they intend to use it to
@@ -458,17 +471,17 @@ instead. See additional CSSWG discussion [here](https://github.com/w3c/csswg-dra
458471
A common usage pattern for scroll-linked animation is to start animation when an element enters
459472
scrollport (or viewport) until it leaves viewport. The current proposal achieves this by allowing
460473
start/end offset to be declared in terms of intersection of the scroller and one of its
461-
descendants. This is still a work in progress but most of the details are spelled out
474+
descendants. This is still a work-in-progress but most of the details are spelled out
462475
[here](https://github.com/w3c/csswg-drafts/issues/4337).
463476
464477
Below are alternatives we have considered:
465478
466479
1. Only expose static offsets and leave it to authors to compute these offset based on element and
467480
scroller bounding client rects. While this seems simple on surface but putting the onus on
468-
authors has a number of problems: Also requiring getBoundingClientRect usage can cause layout
469-
thrashing if not careful. Anything else that affects layout, e.g. new content added to the page
470-
may invalidate these offsets. Authors have to ensure they correctly recompute these offsets.
471-
Some size changes (e.g. zooms) may not be easily detectable.
481+
authors has a number of problems: Also requiring `getBoundingClientRect()` usage can cause layout
482+
thrashing if not careful. Anything else that affects layout such as new content added to the page
483+
may invalidate these offsets. So authors have to ensure they correctly recompute these offsets.
484+
Worst still, some size changes such as ping-zooms may not be easily detectable.
472485
473486
2. Use scroll-snap like alignment syntax (at the moment only exists in CSS). This may be a viable
474487
alternative compared to intersection observer style syntax (at the moment only exists in JS).
@@ -479,7 +492,7 @@ Below are alternatives we have considered:
479492
## CSS animation-timebase
480493
481494
This is an [idea](https://lists.w3.org/Archives/Public/www-style/2014Sep/0135.html) that most
482-
closely matches the spirit of this current proposal. It proposed css syntax that allow animations
495+
closely matches the spirit of this current proposal. It proposed css syntax that allows animations
483496
to be scrubbed in response to scroll. It also suggests a syntax for trigger. The current proposal
484497
captures most of the functionality proposed for animation-timebase and defines exactly how it
485498
integrates with web animations.
@@ -488,7 +501,7 @@ integrates with web animations.
488501
### Exposed Scroll Offset in Worker/Worklet
489502
This is an idea that was first proposed in Compositor Worker and then was explored more in [Houdini
490503
Animation Worklet](https://github.com/w3c/css-houdini-drafts/tree/master/css-animationworklet). The
491-
idea was to simply expose scroll offset to special JS based `animate` callbacks that can run off
504+
idea was to simply expose scroll offset to special JS based `animate()` callbacks that can run off
492505
thread. We believe ScrollTimeline can be used in conjunction with Houdini Animation Worklet thus
493506
there is no need to expose scroll offsets directly. This can enable more complex scroll-linked
494507
animations using Animation Worklet while also making it easy to create fully declarative animations
@@ -498,8 +511,8 @@ for common simpler use cases via Web Animations.
498511
499512
Another [take on this idea](https://github.com/w3c/csswg-drafts/issues/2493) was to change Web
500513
Animations time value to no longer be scalar but value could be a bag of values which may be scroll
501-
positions, touch position etc. This combined with custom js animation callback (e.g., Animation
502-
Worklet) could allow very sophisticated scroll-linked animations but this was also scrapped as we
514+
positions, touch position etc. This combined with custom js animation callback, such as Animation
515+
Worklet, could allow very sophisticated scroll-linked animations but this was also scrapped as we
503516
believed this may not be compatible with the Web Animation model.
504517
505518

0 commit comments

Comments
 (0)