1
1
2
2
# Scroll-linked Animations Explainer
3
3
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.
5
6
6
7
## Participate
7
8
[ 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/
11
12
Scroll-linked animations are a common UX pattern on the web. We are proposing a new API that works
12
13
in conjunction with existing [ Web Animations] ( https://drafts.csswg.org/web-animations/ ) and [ CSS
13
14
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
15
16
[ AnimationTimeline] ( https://drafts.csswg.org/web-animations/#timelines ) is the source of time
16
17
progress that drives the animations. ScrollTimeline is a new timeline whose function is to
17
18
translate “changes in scroll position” of an element into “changes in time”. This allows animations
18
19
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.
20
21
21
22
## Motivating Use Cases and Goals
22
23
@@ -25,22 +26,24 @@ Scroll-linked animated effect are common in web design:
25
26
* Reveal/Unreveal effects
26
27
* Image Zoom effects
27
28
* Progress-bar animations
28
- * Before/After panoramas
29
+ * Scroll-driven Before/After Image slider
29
30
* Creative scroll-driven story-telling
30
31
31
32
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
37
40
difficult] ( https://developers.google.com/web/updates/2016/12/performant-parallaxing ) .
38
41
39
42
40
43
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.
44
47
45
48
### Non-goals
46
49
* ** Scroll-triggered animations** : these are time-based animations that may be triggered when a
@@ -52,8 +55,8 @@ controlled via a common animations API.
52
55
ScrollTimeline proposal does not prohibit.
53
56
54
57
* ** 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
57
60
be made more efficient with [ CSS Animation
58
61
Worklet] ( https://drafts.css-houdini.org/css-animationworklet/ ) ). ScrollTimeline may be used in
59
62
conjunction with these.
@@ -120,11 +123,11 @@ A ScrollTimeline is specified by a number of parameters:
120
123
121
124
#### CSS syntax
122
125
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
124
127
scroll-linked animation to be specified in CSS.
125
128
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.
128
131
129
132
``` css
130
133
#target {
@@ -214,11 +217,11 @@ const scroller = document.getElementById("scroller");
214
217
const image = document.getElementById("image");
215
218
216
219
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
218
221
// to enter scrollport (i .e ., 0% intersect with scroller at its “end ” edge ).
219
222
start : { target: image, edge: ' end' , threshold: 0 },
220
223
221
- // timeline ends at the offset that corresponds with image becoming
224
+ // Timeline ends at the offset that corresponds with image becoming
222
225
// fully visible (i .e ., 100% intersect with scroller at its “end” edge).
223
226
end: { target : image, edge: ' end' , threshold: 1 },
224
227
});
@@ -243,10 +246,10 @@ polyfill](https://flackr.github.io/scroll-timeline/demo/parallax/index.html).
243
246
### Scenario 1 - Parallax
244
247
245
248
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
247
250
[site ](https://www.android .com/android-10 /) for an example of this.
248
251
249
- 
252
+ 
250
253
251
254
To create a parallax effect with ScrollTimeline APIs, one can simply do:
252
255
@@ -270,7 +273,7 @@ often used to create interactive stories. For example see how New York Times app
270
273
animations for creative
271
274
[ storytelling] ( http://www.nytimes.com/projects/2013/tomato-can-blues/index.html ) .
272
275
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 )
274
277
275
278
276
279
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({
324
327
This is another common usage pattern when an image scales up to fill a larger canvas. For an
325
328
example of this see [iPhone 11 launch site](https://www.apple.com/iphone-11/).
326
329
327
- 
330
+ 
328
331
329
332
In this example we start scaling a DIV as soon as its container fully enters the scrollport and
330
333
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:
365
368
addresses this issue among other benefits.
366
369
367
370
* **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.
372
376
373
- * **Dynamic Scrollability**: It is possible for an scroller to no longer
377
+ * **Dynamic Scrollability**: It is possible for a scroller to no longer
374
378
overflow (`overflow: auto`). It is not clear how best to model this behavior.
375
379
One option is to model this as an idle timeline. One current limitation of web
376
380
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
383
387
layout cycles, where a change to a scroll offset causes an animation’s effect to update, which in
384
388
turn causes a new change to the scroll offset. Imagine that an animation shrinks the height of the
385
389
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()`
388
395
callbacks are run. If the sampling of such an animation causes a change to a scroll offset, the
389
396
animation will not be re-sampled to reflect the new offset until the next frame.
390
397
391
398

392
399
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
+
401
406
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.
402
411
403
412
### 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
+
406
419
1. The scroll-linked effects are expressed declaratively similar to other
407
420
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
413
424
per main-thread animation frame and use the last known scroll offset.
414
425
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.
419
433
420
434
### Progress-Based Animations
421
435
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).
429
442
430
443
### Access top-level window scroll in iframes
431
444
432
445
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)
437
450
438
451
### Logical Scrolling vs Animation of Physical properties
439
452
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
441
454
clearly with it. The issue is that many CSS properties, most predominantly transform, are physical
442
455
but ScrollTimeline orientation is logical in that it can be affected by writing-mode). So authors
443
456
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
458
471
A common usage pattern for scroll-linked animation is to start animation when an element enters
459
472
scrollport (or viewport) until it leaves viewport. The current proposal achieves this by allowing
460
473
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
462
475
[here](https://github.com/w3c/csswg-drafts/issues/4337).
463
476
464
477
Below are alternatives we have considered:
465
478
466
479
1. Only expose static offsets and leave it to authors to compute these offset based on element and
467
480
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.
472
485
473
486
2. Use scroll-snap like alignment syntax (at the moment only exists in CSS). This may be a viable
474
487
alternative compared to intersection observer style syntax (at the moment only exists in JS).
@@ -479,7 +492,7 @@ Below are alternatives we have considered:
479
492
## CSS animation-timebase
480
493
481
494
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
483
496
to be scrubbed in response to scroll. It also suggests a syntax for trigger. The current proposal
484
497
captures most of the functionality proposed for animation-timebase and defines exactly how it
485
498
integrates with web animations.
@@ -488,7 +501,7 @@ integrates with web animations.
488
501
### Exposed Scroll Offset in Worker/Worklet
489
502
This is an idea that was first proposed in Compositor Worker and then was explored more in [Houdini
490
503
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
492
505
thread. We believe ScrollTimeline can be used in conjunction with Houdini Animation Worklet thus
493
506
there is no need to expose scroll offsets directly. This can enable more complex scroll-linked
494
507
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.
498
511
499
512
Another [take on this idea](https://github.com/w3c/csswg-drafts/issues/2493) was to change Web
500
513
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
503
516
believed this may not be compatible with the Web Animation model.
504
517
505
518
0 commit comments