forked from w3c/csswg-drafts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOverview.bs
1285 lines (1053 loc) · 49.4 KB
/
Overview.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<style>
/* crbug.com/1471465 */
dl.switch > dt {
counter-increment: list-item 0;
}
</style>
<pre class='metadata'>
Title: Scroll-driven Animations
Group: CSSWG
Status: ED
Work Status: revising
Shortname: scroll-animations
Level: 1
Group: CSSWG
TR: https://www.w3.org/TR/scroll-animations-1/
ED: https://drafts.csswg.org/scroll-animations-1/
Abstract: Defines CSS properties and an API for creating animations that are tied to
the scroll offset of a scroll container.
Editor: Brian Birtles, Invited Expert, [email protected], w3cid 43194
Editor: Botond Ballo, Mozilla, [email protected], w3cid 94018
Editor: Antoine Quint, Apple, [email protected], w3cid 51377
Editor: Olga Gerchikov, Microsoft, [email protected], w3cid 121763
Editor: Elika J. Etemad / fantasai, Apple, http://fantasai.inkedblade.net/contact, w3cid 35400
Editor: Robert Flack, Google, w3cid 98451
Former Editor: Majid Valipour, Google, [email protected], w3cid 81464
Former editor: Mantaroh Yoshinaga
Former editor: Stephen McGruer, Google, [email protected]
Markup Shorthands: markdown yes
</pre>
<pre class=anchors>
urlPrefix: https://html.spec.whatwg.org/multipage/window-object.html; type: dfn; spec: html
text: document associated with a window; url: concept-document-window
urlPrefix: https://drafts.csswg.org/web-animations-2/; type: dfn; spec: web-animations-2
text: calculating an auto-aligned start time
</pre>
<pre class=link-defaults>
spec:web-animations-1;
type:interface; text:AnimationTimeline
type:attribute; text:currentTime
type:dfn;
text:current time
text:active interval
text:start delay
text:end delay
text:active duration
text:iteration count
text:iteration duration
text:finished play state
text:play state
text:start time
text:effective playback rate
text:effect value
spec:html;
type:dfn; for:/; text:browsing context
type:method; text:requestAnimationFrame()
spec: cssom-view-1; type: dfn;
text: overflow direction;
text: css layout box
spec:css-writing-modes-4; type: dfn;
text:start
text:end
spec:infra; type:dfn; text:user agent
spec:selectors-4; type:dfn; text:selector
</pre>
# Introduction # {#intro}
This specification defines mechanisms for
driving the progress of an animation
based on the scroll progress of a scroll container.
These <dfn export>scroll-driven animations</dfn>
use a timeline based on scroll position,
rather than one based on clock time.
This module provides both an imperative API building on the Web Animations API
as well as a declarative API building on CSS Animations.
<!-- [[!CSS-ANIMATIONS-2]] bikeshed chokes on this -->
[[!WEB-ANIMATIONS-1]]
There are two types of <dfn export>scroll-driven timelines</dfn>:
* [[#scroll-timelines|Scroll Progress Timelines]],
which are linked to the scroll progress of a particular [=scroll container=]
* [[#view-timelines|View Progress Timelines]],
which are linked to the view progress of a particular [=box=] through a [=scrollport=]
Note: Scroll-<em>driven</em> animations,
whose progress is linked to the scroll position,
are distinct from scroll-<em>triggered</em> animations,
which are triggered by a scroll position,
but whose progress is driven by time.
## Relationship to other specifications ## {#other-specs}
Web Animations [[WEB-ANIMATIONS-1]] defines
an abstract conceptual model for animations on the Web platform,
with elements of the model including [=animations=] and their [=timelines=],
and associated programming interfaces.
This specification extends the Web Animations model
by defining [=scroll-driven timelines=]
and allowing them to drive progress in [=animations=]
to create [=scroll-driven animations=].
This specification introduces both
programming interfaces for interacting with these concepts,
as well as CSS properties that apply these concepts
to CSS Animations [[CSS-ANIMATIONS-1]].
To the extent the behavior of these CSS properties is described
in terms of the programming interfaces,
[=User Agents=] that do not support scripting
may still conform to this specification
by implementing the CSS features to behave
as if the underlying programming interfaces were in place.
Like most operations in CSS besides [=selector=] matching,
features in this specification operate over
the [=flattened element tree=].
## Relationship to asynchronous scrolling ## {#async-scrolling}
Some user agents support scrolling that is asynchronous
with respect to layout or script.
This specification is intended to be compatible with such an architecture.
Specifically, this specification allows expressing scroll-driven effects
in a way that does not require script to run each time the effect is sampled.
User agents that support asynchronous scrolling are allowed (but not required)
to sample such effects asynchronously as well.
## Value Definitions ## {#values}
This specification follows the
<a href="https://www.w3.org/TR/CSS2/about.html#property-defs">CSS property definition conventions</a>
from [[!CSS2]]
using the <a href="https://www.w3.org/TR/css-values-3/#value-defs">value definition syntax</a>
from [[!CSS-VALUES-3]].
Value types not defined in this specification
are defined in CSS Values & Units [[!CSS-VALUES-3]].
Combination with other CSS modules may expand the definitions of these value types.
In addition to the property-specific values listed in their definitions,
all properties defined in this specification
also accept the <a>CSS-wide keywords</a> as their property value.
For readability they have not been repeated explicitly.
# Scroll Progress Timelines # {#scroll-timelines}
<dfn export>Scroll progress timelines</dfn>
are timelines linked to progress
in the scroll position of a [=scroll container=]
along a particular axis.
The startmost scroll position represents 0% progress
and the endmost scroll position represents 100% progress.
[=Scroll progress timelines=] can be referenced in 'animation-timeline'
anonymously using the ''scroll()'' [=functional notation=]
or by name (see [[#timeline-scoping]])
after declaring them using the 'scroll-timeline' properties.
In the Web Animations API,
they can be represented anonymously by a {{ScrollTimeline}} object.
## Calculating Progress for a Scroll Progress Timeline ## {#scroll-timeline-progress}
Progress (the [=timeline/current time=]) for a [=scroll progress timeline=]
is calculated as:
<var ignore=''>[=scroll offset=]</var> ÷
(<var ignore=''>[=scrollable overflow=] size</var> −
<var ignore=''>[=scroll container=] size</var>)
If the 0% position and 100% position coincide
(i.e. the denominator in the [=timeline/current time=] formula is zero),
the timeline is [=inactive timeline|inactive=].
In [=paged media=],
[=scroll progress timelines=] that would otherwise reference the document viewport
are also [=inactive timeline|inactive=].
## Anonymous Scroll Progress Timelines ## {#scroll-timelines-anonymous}
### The ''scroll()'' notation ### {#scroll-notation}
The <dfn>scroll()</dfn> functional notation
can be used as a <<single-animation-timeline>> value in 'animation-timeline'
and specifies a [=scroll progress timeline=].
Its syntax is
<pre class="prod">
<<scroll()>> = scroll( [ <<scroller>> || <<axis>> ]? )
<dfn noexport><<axis>></dfn> = block | inline | x | y
<dfn noexport><<scroller>></dfn> = root | nearest | self
</pre>
By default,
''scroll()'' references the [=block axis=] of the nearest ancestor [=scroll container=].
Its arguments modify this lookup as follows:
<dl dfn-type=value dfn-for="scroll(),scroll-timeline-axis,view-timeline-axis">
<dt><dfn>block</dfn>
<dd>
Specifies to use the measure of progress along the
[=block axis=] of the [=scroll container=].
(Default.)
<dt><dfn>inline</dfn>
<dd>
Specifies to use the measure of progress along the
[=inline axis=] of the [=scroll container=].
<dt><dfn>x</dfn>
<dd>
Specifies to use the measure of progress along the
[=horizontal axis=] of the [=scroll container=].
<dt><dfn>y</dfn>
<dd>
Specifies to use the measure of progress along the
[=vertical axis=] of the [=scroll container=].
<dt><dfn>nearest</dfn>
<dd>
Specifies to use the nearest ancestor [=scroll container=].
(Default.)
<dt><dfn>root</dfn>
<dd>
Specifies to use the document viewport as the [=scroll container=].
<dt><dfn>self</dfn>
<dd>
Specifies to use the element’s own [=principal box=] as the [=scroll container=].
If the [=principal box=] is not a [=scroll container=],
then the [=scroll progress timeline=] is [=inactive timeline|inactive=].
</dl>
Note: Progress is in reference to the [=scroll origin=],
which can flip depending on [=writing mode=],
even when ''scroll-timeline-axis/x'' or ''scroll-timeline-axis/y'' is specified.
References to the [=root element=] propagate to the document viewport
(which functions as its [=scroll container=]).
Each use of ''scroll()'' corresponds to its own instance of {{ScrollTimeline}}
in the Web Animations API,
even if multiple elements use ''scroll()'' to refer
to the same [=scroll container=] with the same arguments.
### The {{ScrollTimeline}} Interface ### {#scrolltimeline-interface}
<pre class="idl">
enum ScrollAxis {
"block",
"inline",
"x",
"y"
};
dictionary ScrollTimelineOptions {
Element? source;
ScrollAxis axis = "block";
};
[Exposed=Window]
interface ScrollTimeline : AnimationTimeline {
constructor(optional ScrollTimelineOptions options = {});
readonly attribute Element? source;
readonly attribute ScrollAxis axis;
};
</pre>
A {{ScrollTimeline}} is an {{AnimationTimeline}}
that represents a [=scroll progress timeline=].
It can be passed to
the {{Animation}} constructor or the {{Animatable/animate()}} method
to link the animation to a [=scroll progress timeline=].
<dl class="attributes" dfn-type=attribute dfn-for=ScrollTimeline>
: <dfn>source</dfn>
:: The [=scroll container=] element
whose scroll position drives the progress of the timeline.
: <dfn>axis</dfn>
:: The axis of scrolling
that drives the progress of the timeline.
See value definitions for <<axis>>, above.
</dl>
Inherited attributes:
<dl>
: {{AnimationTimeline/currentTime}} (inherited from {{AnimationTimeline}})
:: Represents the scroll progress of the [=scroll container=]
as a percentage CSSUnitValue,
with 0% representing its startmost scroll position
(in the [=writing mode=] of the [=scroll container=]).
Null when the timeline is [=inactive timeline|inactive=].
</dl>
ISSUE: While 0% will usually represent the [=scroll container=]’s initial scroll position,
it might not depending on its [=content distribution=].
See [[css-align-3#overflow-scroll-position]].
Is this what we want?
<!-- turn this into a note instead of a question once resolved -->
ISSUE: Add a note about whether {{AnimationTimeline/currentTime}}
can be negative or > 100%.
<dl class="constructors">
: <dfn constructor for=ScrollTimeline lt="ScrollTimeline(options)">ScrollTimeline(options)</dfn>
:: Creates a new {{ScrollTimeline}} object using the following procedure:
1. Let |timeline| be the new {{ScrollTimeline}} object.
1. Set the {{ScrollTimeline/source}} of |timeline| to:
<dl class="switch">
: If the `source` member of |options| is present,
:: The `source` member of |options|.
: Otherwise,
:: The {{Document/scrollingElement}}
of the {{Document}} <a lt="document associated with a window">associated</a>
with the {{Window}} that is the <a>current global object</a>.
</dl>
1. Set the {{ScrollTimeline/axis}} property of |timeline|
to the corresponding value from |options|.
</dl>
If the {{ScrollTimeline/source}} of a {{ScrollTimeline}}
is an element whose [=principal box=] does not exist
or is not a [=scroll container=],
or if there is no [=scrollable overflow=],
then the {{ScrollTimeline}} is [=inactive timeline|inactive=].
A {{ScrollTimeline}}’s {{AnimationTimeline/duration}} is 100%.
The values of {{ScrollTimeline/source}} and {{AnimationTimeline/currentTime}}
are both computed when either is requested or updated.
## Named Scroll Progress Timelines ## {#scroll-timelines-named}
[=Scroll progress timelines=] can also be defined on the [=scroll container=] itself,
and then referenced by name
by elements within the name’s scope
(see [[#timeline-scoping]]).
Such <dfn>named scroll progress timelines</dfn>
are declared in the [=coordinated value list=]
constructed from the [=longhands=] of the 'scroll-timeline' [=shorthand property=],
which form a [=coordinating list property group=]
with 'scroll-timeline-name' as the [=coordinating list base property=].
See [[css-values-4#linked-properties]].
### Naming a Scroll Progress Timeline: the 'scroll-timeline-name' property ### {#scroll-timeline-name}
<pre class='propdef'>
Name: scroll-timeline-name
Value: [ none | <<dashed-ident>> ]#
Initial: none
Applies to: all elements
Inherited: no
Computed value: the keyword ''scroll-timeline-name/none'' or a list of [=CSS identifiers=]
Animation type: not animatable
</pre>
Specifies names for the [=named scroll progress timelines=]
associated with this element.
### Axis of a Scroll Progress Timeline: the 'scroll-timeline-axis' property ### {#scroll-timeline-axis}
<pre class='propdef'>
Name: scroll-timeline-axis
Value: [ block | inline | x | y ]#
Initial: block
Applies to: all elements
Inherited: no
Computed value: a list of the keywords specified
Animation type: not animatable
</pre>
Specifies the axis of any [=named scroll progress timelines=]
sourced from this [=scroll container=].
If this box is not a [=scroll container=],
then the corresponding [=named scroll progress timeline=]
is [=inactive timeline|inactive=].
Values are as defined for ''scroll()''.
### Scroll Timeline Shorthand: the 'scroll-timeline' shorthand ### {#scroll-timeline-shorthand}
<pre class='propdef shorthand'>
Name: scroll-timeline
Value: [ <<'scroll-timeline-name'>> <<'scroll-timeline-axis'>>? ]#
Applies to: all elements
Inherited: no
Animation type: not animatable
</pre>
This property is a [=shorthand=] for setting
'scroll-timeline-name' and 'scroll-timeline-axis'
in a single declaration.
# View Progress Timelines # {#view-timelines}
Often animations are desired to start and end
during the portion of the [=scroll progress timeline=]
that a particular box
(the <dfn>view progress subject</dfn>)
is in view within the [=scrollport=].
<dfn export>View progress timelines</dfn>
are segments of a [=scroll progress timeline=]
that are scoped to the scroll positions
in which any part of the subject element’s [=principal box=]
intersects its nearest ancestor [=scrollport=]
(or more precisely, the relevant [=view progress visibility range=]
of that [=scrollport=]).
The startmost such scroll position represents 0% progress,
and the endmost such scroll position represents 100% progress;
see [[#view-timeline-progress]].
Note: The 0% and 100% scroll positions are not always reachable,
e.g. if the box is positioned
at the start edge of the [=scrollable overflow rectangle=],
it might not be possible to scroll to < 32% progress.
[=View progress timelines=] can be referenced
anonymously using the ''view()'' [=functional notation=]
or by name (see [[#timeline-scoping]])
after declaring them using the 'view-timeline' properties
on the [=view progress subject=].
In the Web Animations API,
they can be represented anonymously by a {{ViewTimeline}} object.
## View Progress Timeline Ranges ## {#view-timelines-ranges}
[=View progress timelines=] define the following [=named timeline ranges=]:
<dl dfn-for="animation-timeline-range" dfn-type="value">
<dt><dfn>cover</dfn>
<dd>
Represents the full range of the [=view progress timeline=]:
* 0% progress represents the latest position at which
the [=start=] [=border edge=] of the element’s [=principal box=]
coincides with the [=end=] edge of its [=view progress visibility range=].
* 100% progress represents the earliest position at which
the [=end=] [=border edge=] of the element’s [=principal box=]
coincides with the [=start=] edge of its [=view progress visibility range=].
<dt><dfn>contain</dfn>
<dd>
Represents the range during which the [=principal box=]
is either fully contained by, or fully covers,
its [=view progress visibility range=] within the [=scrollport=].
* 0% progress represents the earliest position at which either:
* the [=start=] [=border edge=] of the element’s [=principal box=]
coincides with the [=start=] edge of its [=view progress visibility range=].
* the [=end=] [=border edge=] of the element’s [=principal box=]
coincides with the [=end=] edge of its [=view progress visibility range=].
* 100% progress represents the latest position at which either:
* the [=start=] [=border edge=] of the element’s [=principal box=]
coincides with the [=start=] edge of its [=view progress visibility range=].
* the [=end=] [=border edge=] of the element’s [=principal box=]
coincides with the [=end=] edge of its [=view progress visibility range=].
<dt><dfn>entry</dfn>
<dd>
Represents the range during which the [=principal box=]
is entering the [=view progress visibility range=].
* 0% is equivalent to 0% of the ''animation-timeline-range/cover'' range.
* 100% is equivalent to 0% of the ''animation-timeline-range/contain'' range.
<dt><dfn>exit</dfn>
<dd>
Represents the range during which the [=principal box=]
is exiting the [=view progress visibility range=].
* 0% is equivalent to 100% of the ''animation-timeline-range/contain'' range.
* 100% is equivalent to 100% of the ''animation-timeline-range/cover'' range.
<dt><dfn>entry-crossing</dfn>
<dd>
Represents the range during which the [=principal box=] crosses the [=end=]
[=border edge=]
* 0% progress represents the latest position at which
the [=start=] [=border edge=] of the element’s [=principal box=]
coincides with the [=end=] edge of its [=view progress visibility range=].
* 100% progress represents the earliest position at which
the [=end=] [=border edge=] of the element’s [=principal box=]
coincides with the [=end=] edge of its [=view progress visibility range=].
<dt><dfn>exit-crossing</dfn>
<dd>
Represents the range during which the [=principal box=] crosses the [=start=]
[=border edge=]
* 0% progress represents the latest position at which
the [=start=] [=border edge=] of the element’s [=principal box=]
coincides with the [=start=] edge of its [=view progress visibility range=].
* 100% progress represents the earliest position at which
the [=end=] [=border edge=] of the element’s [=principal box=]
coincides with the [=start=] edge of its [=view progress visibility range=].
</dl>
ISSUE: Insert diagrams.
In all cases, the [=writing mode=] used to resolve the [=start=] and [=end=] sides
is the [=writing mode=] of the relevant [=scroll container=].
<a href="http://www.w3.org/TR/css-transforms/">Transforms</a> are ignored,
but [=relative positioning|relative=] and [=absolute positioning|absolute=] positioning
are accounted for.
Note: For [=sticky-positioned boxes=]
the 0% and 100% progress conditions can sometimes be satisfied
by a range of scroll positions rather than just one.
Each range therefore indicates whether to use
the earliest or latest qualifying position.
[[CSS-POSITION-3]] [[CSS-TRANSFORMS-1]]
## Calculating Progress for a View Progress Timeline ## {#view-timeline-progress}
Progress (the [=timeline/current time=]) in a [=view progress timeline=]
is calculated as:
|distance| ÷ |range|
where:
* |distance| is the current [=scroll offset=]
minus the [=scroll offset=] corresponding to
the start of the ''animation-timeline-range/cover'' range
* |range| is
the [=scroll offset=] corresponding to
the start of the ''animation-timeline-range/cover'' range
minus
the [=scroll offset=] corresponding to
the end of the ''animation-timeline-range/cover'' range
If the 0% position and 100% position coincide
(i.e. the denominator in the [=timeline/current time=] formula is zero),
the timeline is [=inactive timeline|inactive=].
In [=paged media=],
[=view progress timelines=] that would otherwise reference the document viewport
are also [=inactive timeline|inactive=].
## Anonymous View Progress Timelines ## {#view-timelines-anonymous}
### The ''view()'' notation ### {#view-notation}
The <dfn>view()</dfn> functional notation
can be used as a <<single-animation-timeline>> value in 'animation-timeline'
and specifies a [=view progress timeline=]
in reference to the nearest ancestor [=scroll container=].
Its syntax is
<pre class="prod">
<<view()>> = view( [ <<axis>> || <<'view-timeline-inset'>> ]? )
</pre>
By default,
''view()'' references the [=block axis=];
as for ''scroll()'',
this can be changed by providing an explicit <<axis>> value.
The optional <<'view-timeline-inset'>> value provides an adjustment
of the [=view progress visibility range=],
as defined for 'view-timeline-inset'.
Each use of ''view()'' corresponds to its own instance of {{ViewTimeline}}
in the Web Animations API,
even if multiple elements use ''view()'' to reference
the same element with the same arguments.
### The {{ViewTimeline}} Interface ### {#viewtimeline-interface}
<pre class="idl">
dictionary ViewTimelineOptions {
Element subject;
ScrollAxis axis = "block";
(DOMString or sequence<(CSSNumericValue or CSSKeywordValue)>) inset = "auto";
};
[Exposed=Window]
interface ViewTimeline : ScrollTimeline {
constructor(optional ViewTimelineOptions options = {});
readonly attribute Element subject;
readonly attribute CSSNumericValue startOffset;
readonly attribute CSSNumericValue endOffset;
};
</pre>
A {{ViewTimeline}} is an {{AnimationTimeline}}
that specifies a [=view progress timeline=].
It can be passed to
the {{Animation}} constructor or the {{Animatable/animate()}} method
to link the animation to a [=view progress timeline=].
<dl class="attributes" dfn-type=attribute dfn-for=ViewTimeline>
: <dfn>subject</dfn>
:: The element whose [=principal box=]’s visibility in the [=scrollport=]
defines the progress of the timeline.
: <dfn>startOffset</dfn>
:: Represents the starting (0% progress) scroll position
of the [=view progress timeline=]
as a length offset (in ''px'') from the [=scroll origin=].
Null when the timeline is [=inactive timeline|inactive=].
: <dfn>endOffset</dfn>
:: Represents the ending (100% progress) scroll position
of the [=view progress timeline=]
as a length offset (in ''px'') from the [=scroll origin=].
Null when the timeline is [=inactive timeline|inactive=].
</dl>
Note: The values of {{ViewTimeline/startOffset}} and {{ViewTimeline/endOffset}}
are relative to the [=scroll origin=], not the [=physical=] top left corner.
Depending on the [=writing mode=] of the [=scroll container=],
they therefore might not match {{Element/scrollLeft}} or {{Element/scrollTop}} values,
for example in the [=horizontal axis=] in a right-to-left (''rtl'') [=writing mode=].
Inherited attributes:
<dl>
: {{ScrollTimeline/source}} (inherited from {{ScrollTimeline}})
:: The nearest ancestor of the {{ViewTimeline/subject}}
whose [=principal box=] establishes a [=scroll container=],
whose scroll position drives the progress of the timeline.
: {{ScrollTimeline/axis}} (inherited from {{ScrollTimeline}})
:: Specifies the axis of scrolling
that drives the progress of the timeline.
See <<axis>>, above.
: {{AnimationTimeline/currentTime}} (inherited from {{AnimationTimeline}})
:: Represents the current progress
of the [=view progress timeline=]
as a percentage {{CSSUnitValue}}
representing its [=scroll container=]’s scroll progress at that position.
Null when the timeline is [=inactive timeline|inactive=].
</dl>
<dl class="constructors">
: <dfn constructor for=ViewTimeline lt="ViewTimeline(options)">ViewTimeline(options)</dfn>
:: Creates a new {{ViewTimeline}} object using the following procedure:
1. Let |timeline| be the new {{ViewTimeline}} object.
1. Set the {{ViewTimeline/subject}} and {{ScrollTimeline/axis}} properties of |timeline|
to the corresponding values from |options|.
1. Set the {{ScrollTimeline/source}} of |timeline|
to the {{ViewTimeline/subject}}’s
nearest ancestor [=scroll container=] element.
1. If a {{DOMString}} value is provided as an inset,
parse it as a <<'view-timeline-inset'>> value;
if a sequence is provided,
the first value represents the start inset
and the second value represents the end inset.
If the sequence has only one value,
it is duplicated.
If it has zero values or more than two values,
or if it contains a {{CSSKeywordValue}} whose {{CSSKeywordValue/value}} is not "auto",
throw a <span class="exceptionname">TypeError</span>.
These insets define the {{ViewTimeline}}’s [=view progress visibility range=].
</dl>
If the {{ScrollTimeline/source}} or {{ViewTimeline/subject}} of a {{ViewTimeline}}
is an element whose [=principal box=] does not exist,
or if its nearest ancestor [=scroll container=] has no [=scrollable overflow=]
(or if there is no such ancestor, e.g. in print media),
then the {{ViewTimeline}} is [=inactive timeline|inactive=].
The values of {{ViewTimeline/subject}}, {{ScrollTimeline/source}}, and {{AnimationTimeline/currentTime}}
are all computed when any of them is requested or updated.
## Named View Progress Timelines ## {#view-timelines-named}
[=View progress timelines=] can also be defined declaratively
and then referenced by name
by elements within the name’s scope
(see [[#timeline-scoping]]).
Such <dfn>named view progress timelines</dfn>
are declared in the [=coordinated value list=]
constructed from the 'view-timeline-*' properties,
which form a [=coordinating list property group=]
with 'view-timeline-name' as the [=coordinating list base property=].
See [[css-values-4#linked-properties]].
### Naming a View Progress Timeline: the 'view-timeline-name' property ### {#view-timeline-name}
<pre class='propdef'>
Name: view-timeline-name
Value: [ none | <<dashed-ident>> ]#
Initial: none
Applies to: all elements
Inherited: no
Computed value: the keyword ''view-timeline-name/none'' or a list of [=CSS identifiers=]
Animation type: not animatable
</pre>
Specifies names for the [=named view progress timelines=]
associated with this element.
### Axis of a View Progress Timeline: the 'view-timeline-axis' property ### {#view-timeline-axis}
<pre class='propdef'>
Name: view-timeline-axis
Value: [ block | inline | x | y ]#
Initial: block
Applies to: all elements
Inherited: no
Computed value: a list of the keywords specified
Animation type: not animatable
</pre>
Specifies the axis of any [=named view progress timelines=]
derived from this element’s [=principal box=].
Values are as defined for ''view()''.
### Inset of a View Progress Timeline: the 'view-timeline-inset' property ### {#view-timeline-inset}
<pre class='propdef'>
Name: view-timeline-inset
Value: [ [ auto | <<length-percentage>> ]{1,2} ]#
Initial: auto
Applies to: all elements
Inherited: no
Percentages: relative to the corresponding dimension of the relevant scrollport
Computed value: a list consisting of two-value pairs representing the start and end insets each as either the keyword ''view-timeline-inset/auto'' or a computed <<length-percentage>> value
Animation type: by computed value type
</pre>
Specifies an inset (positive) or outset (negative) adjustment of the [=scrollport=]
when determining whether the box is in view
when setting the bounds of the corresponding [=view progress timeline=].
The first value represents the [=start=] inset in the relevant axis;
the second value represents the [=end=] inset.
If the second value is omitted, it is set to the first.
The resulting range of the [=scrollport=] is
the <dfn>view progress visibility range</dfn>.
<dl dfn-for=view-timeline-inset dfn-type=value>
<dt><dfn>auto</dfn>
<dd>
Indicates to use the value of 'scroll-padding'.
<dt><dfn><<length-percentage>></dfn>
<dd>
Like 'scroll-padding',
defines an inward offset from the corresponding edge of the scrollport.
</dl>
### View Timeline Shorthand: the 'view-timeline' shorthand ### {#view-timeline-shorthand}
<pre class='propdef shorthand'>
Name: view-timeline
Value: [ <<'view-timeline-name'>> [ <<'view-timeline-axis'>> || <<'view-timeline-inset'>> ]? ]#
Applies to: all elements
</pre>
This property is a [=shorthand=] for setting
'view-timeline-name', 'view-timeline-axis', and 'view-timeline-inset'
in a single declaration.
# Attaching Animations to [=Scroll-driven Timelines=] # {#scroll-driven-attachment}
Animations can be attached to [=scroll-driven timelines=]
using the 'scroll-timeline' property (in CSS)
or the {{AnimationTimeline}} parameters (in the Web Animations API).
The timeline range to which their [=active interval=] is attached
can also be further restricted to a particular timeline range
(see [[#named-range-animation-declaration]]).
Time-based delays ('animation-delay')
get converted to their respective proportions
as described in [[web-animations-2#animations]]
## Finite Timeline Calculations ## {#finite-attachment}
Unlike time-driven timelines,
[=scroll-driven timelines=] are finite,
thus [=scroll-driven animations=] are always attached
to a finite [=attachment range=]--
which may be further limited by 'animation-range'
(see [[#timeline-ranges]]).
The animation’s <!-- delays ('animation-delay') and -->
iterations ('animation-iteration-count')
are set within the limits of this finite range.
If the specified duration is ''animation-duration/auto'',
then <!-- once any delays are subtracted, -->
the remaining range is divided by its [=iteration count=] ('animation-iteration-count')
to find the [=used value|used=] duration.
Note: If the animation has an infinite [=iteration count=],
each [=iteration duration=]--
and the resulting [=active duration=]--
will be zero.
Animations that include absolutely-positioned keyframes
(those pinned to a specific point on the timeline,
e.g. using [[#named-range-keyframes|named timeline range keyframe selectors]] in ''@keyframes'')
are assumed to have an [=iteration count=] of 1
for the purpose of finding those keyframes’ positions
relative to 0% and 100%;
the entire animation is then scaled to fit the [=iteration duration=]
and repeated for each iteration.
Note: It's unclear what the use case might be
for combining absolutely-positioned keyframes
with iteration counts above 1;
this at least gives a defined behavior.
(An alternative, but perhaps weirder, behavior
would be to take such absolutely-positioned keyframes
“out of flow” while iterating the remaining keyframes.)
The editors would be interested in hearing about
any real use cases for multiple iterations here.
## Named Timeline Scoping and Lookup ## {#timeline-scoping}
A named [=scroll progress timeline=] or [=view progress timeline=]
is referenceable by:
* the name-declaring element itself
* that element’s descendants
Note: The 'timeline-scope' property can be used
to declare the name of a timeline on an ancestor of its defining element,
effectively expanding its scope beyond that element’s subtree.
If multiple elements have declared the same timeline name,
the matching timeline is the one declared
on the nearest element in tree order.
In case of a name conflict on the same element,
names declared later in the naming property
('scroll-timeline-name', 'view-timeline-name')
take precedence, and
[=scroll progress timelines=] take precedence over [=view progress timelines=].
<div class=example>
Using ''timeline-scope'',
an element can refer to timelines
bound to elements that are siblings, cousins, or even descendants.
For example, the following creates an animation on an element
that is linked to a [=scroll progress timeline=]
defined by the subsequent sibling.
<xmp highlight=html>
<style>
@keyframes anim {
from { color: red; }
to { color: green; }
}
.root {
/* declares the scope of a 'scroller' timeline to reach all descendants */
timeline-scope: scroller;
}
.root .animation {
animation: anim;
/* references the 'scroller' timeline for driving the progress of 'anim' */
animation-timeline: scroller;
}
.root .animation + .scroller {
/* attaches a scroll progress timeline to the timeline name 'scroller' */
scroll-timeline: scroller;
}
</style>
…
<section class="root">
<div class="animation">Animating Box</div>
<div class="scroller">Scrollable Box</div>
</section>
</xmp>
</div>
## Animation Events ## {#events}
[=Scroll-driven animations=] dispatch all the same animation events
as the more typical time-driven animations
as described in
[[web-animations-1#animation-events-section]],
[[css-animations-1#events]],
and [[css-animations-2#event-dispatch]].
Note: When scrolling backwards,
the <code>animationstart</code> event will fire
at the <em>end</em> of the [=active interval=],
and the <code>animationend</code> event will fire
at the start of the [=active interval=].
However, since the <code>finish</code> event
is about entering the [=play state/finished|finished play state=],
it only fires when scrolling forwards.
# Frame Calculation Details # {#frames}
## HTML Processing Model: Event loop ## {#event-loop}
The ability for scrolling to drive the progress of an animation,
gives rise to the possibility of <dfn>layout cycles</dfn>,
where a change to a scroll offset causes an animation's effect to update,
which in turn causes a new change to the scroll offset.
To avoid such [=layout cycles=],
animations with a [=scroll progress timeline=] update their current time once
during step 7.10 of the [HTML Processing Model](https://html.spec.whatwg.org/multipage/webappapis.html#processing-model-8) event loop,
as step 1 of [=update animations and send events=].
During step 7.14.1 of the [HTML Processing Model](https://html.spec.whatwg.org/multipage/webappapis.html#processing-model-8),
any created [=scroll progress timelines=] or [=view progress timelines=] are collected into a <dfn export>stale timelines</dfn> set.
After step 7.14 if any timelines' [=named timeline ranges=] have changed,
these timelines are added to the [=stale timelines=] set.
If there are any [=stale timelines=], they now update their current time and associated ranges,
the set of [=stale timelines=] is cleared and
we run an additional step to recalculate styles and update layout.
Note: We check for layout changes after dispatching any {{ResizeObserver}}s intentionally
to take programmatically sized elements into account.
Note: As we only gather stale timelines during the first style and layout calculation,
this can only directly cause one additional style recalculation.
Other APIs which require another update should be checked in the same step
and be updated at the same time.
Note: Without this additional round of style and layout,
[=stale timelines|initially stale=] timelines would remain stale
(i.e. they would not have a current time)
for the remainder of the frame where the timeline was created.
This means that animations linked to such a timeline
would not produce any [=effect value=] for that frame,
which could lead to an undesirable initial "flash"
in the rendered output.
Note: This section has no effect on forced style and layout
calculations triggered by {{Window/getComputedStyle()|getComputedStyle()}} or similar.
In other words, [=stale timelines|initially stale=] timelines are visible as such
through those APIs.
If the final style and layout update
would result in a change in the time or scope (see 'timeline-scope')
of any [=scroll progress timelines=] or [=view progress timelines=],
they will not be re-sampled to reflect the new state
until the next update of the rendering.
Nothing in this section is intended to require
that scrolling block on layout or script.
If a user agent normally composites frames where scrolling has occurred
but the consequences of scrolling have not been fully propagated in layout or script
(for example, `scroll` event listeners have not yet run),
the user agent may likewise choose not to sample scroll-driven animations
for that composited frame.
In such cases, the rendered scroll offset
and the state of a scroll-driven animation
may be inconsistent in the composited frame.
When updating timeline current time,
the [=start time=] of any attached animation is conditionally updated.
For each attached animation,
run the procedure for [=calculating an auto-aligned start time=].
# Privacy Considerations # {#privacy-considerations}
There are no known privacy impacts of the features in this specification.
# Security Considerations # {#security-considerations}
There are no known security impacts of the features in this specification.
# Appendix A: Timeline Ranges # {#timeline-ranges}
ISSUE: This section should move to CSS-ANIMATIONS-2 and WEB-ANIMATIONS-2.
This appendix introduces the concepts of [=named timeline ranges=]
and [=animation attachment ranges=]
to <a href="https://www.w3.org/TR/css-animations/">CSS Animations</a>
and <a href="https://www.w3.org/TR/web-animations/">Web Animations</a>.
## Named Timeline Ranges ## {#named-ranges}
A <dfn export>named timeline range</dfn>
is a named segment of an animation [=timeline=].
The start of the segment is represented as 0% progress through the range;
the end of the segment is represented as 100% progress through the range.
Multiple [=named timeline ranges=] can be associated with a given [=timeline=],
and multiple such ranges can overlap.
For example, the ''animation-timeline/contain'' range of a [=view progress timeline=]
overlaps with its ''animation-timeline/cover'' range.
[=Named timeline ranges=] are represented by
the <dfn><<timeline-range-name>></dfn> value type,
which indicates a [=CSS identifier=] representing
one of the predefined [=named timeline ranges=].
Note: In this specification, [=named timeline ranges=]
must be defined to exist by a specification
such as [[SCROLL-ANIMATIONS-1]].
A future level may introduce APIs for authors to declare
their own custom [=named timeline ranges=].
## Named Timeline Range Keyframe Selectors ## {#named-range-keyframes}
[=Named timeline range=] names and percentages