@@ -9,7 +9,7 @@ Group: CSSWG
99URL : https://drafts.csswg.org/scroll-animations-1/
1010ED : https://drafts.csswg.org/scroll-animations-1/
1111Shortname : scroll-animations-1
12- Abstract : Defines an API and markup for creating animations that are tied to
12+ Abstract : Defines an API and markup for creating animations that are tied to
1313 the scroll offset of a scroll container.
1414Editor : Brian Birtles, Invited Expert, brian@birchill.co.jp, w3cid 43194
1515Editor : Botond Ballo, Mozilla, botond@mozilla.com
@@ -32,6 +32,7 @@ urlPrefix: https://w3c.github.io/web-animations/; type: dfn; spec: web-animation
3232 text: timeline
3333urlPrefix: https://drafts.csswg.org/cssom-view/; type: dfn; spec: cssom-view-1
3434 text: CSS layout box
35+ text: overflow direction; url: overflow-directions
3536urlPrefix: https://html.spec.whatwg.org/multipage/browsers.html; type: dfn; spec: html
3637 text: document associated with a window; url: concept-document-window
3738</pre>
@@ -216,7 +217,7 @@ Typically, the scroll bar provides this visual indication but
216217applications may wish to hide the scroll bar for aesthetic or useability
217218reasons.
218219
219- Using the updated 'animation' shorthand that includes 'animation-timeline' ,
220+ Using the updated 'animation' shorthand that includes 'animation-timeline' ,
220221this example could be written as follows:
221222
222223<pre class='lang-css'>
@@ -344,8 +345,8 @@ enum ScrollTimelineAutoKeyword { "auto" };
344345dictionary ScrollTimelineOptions {
345346 Element? source = null;
346347 ScrollDirection orientation = "block";
347- DOMString start = "auto";
348- DOMString end = "auto";
348+ ( DOMString or ElementBasedOffset) start = "auto";
349+ ( DOMString or ElementBasedOffset) end = "auto";
349350 (double or ScrollTimelineAutoKeyword) timeRange = "auto";
350351};
351352
@@ -360,8 +361,9 @@ interface ScrollTimeline : AnimationTimeline {
360361};
361362</pre>
362363
363- A <dfn>scroll timeline</dfn> is an {{AnimationTimeline}} whose time values are determined
364- not by wall-clock time, but by the progress of scrolling in a [=scroll container=] .
364+ A <dfn>scroll timeline</dfn> is an {{AnimationTimeline}} whose time values are
365+ determined not by wall-clock time, but by the progress of scrolling in a
366+ [=scroll container=] .
365367
366368<div link-for-hint="ScrollTimeline">
367369
@@ -391,69 +393,224 @@ not by wall-clock time, but by the progress of scrolling in a [=scroll container
391393<div class="attributes">
392394
393395: <dfn attribute for=ScrollTimeline>source</dfn>
394- :: The scrollable element whose scrolling triggers the activation and drives the
395- progress of the timeline.
396+ :: The scrollable element whose scrolling triggers the activation and drives
397+ the progress of the timeline.
396398
397399: <dfn attribute for=ScrollTimeline>orientation</dfn>
398- :: Determines the direction of scrolling which triggers the activation and drives
399- the progress of the timeline.
400+ :: Determines the direction of scrolling which triggers the activation and
401+ drives the progress of the timeline.
400402
401403: <dfn attribute for=ScrollTimeline>start</dfn>
402- :: A scroll offset, in the direction specified by {{orientation}} , which constitutes
403- the beginning of the range in which the timeline is active.
404-
405- Recognized values are defined by the following grammar:
406-
407- <blockquote>
408- <pre class="prod">auto | <<length>> | <<percentage>> </pre>
409- </blockquote>
410-
411- The meaning of each value is as follows:
412-
413- : auto
414- :: The beginning of {{source}} 's scroll range in {{orientation}} .
415- : <<length>>
416- :: An absolute distance along {{source}} 's scroll range in {{orientation}} .
417- : <<percentage>>
418- :: A percentage distance along {{source}} 's scroll range in {{orientation}} .
404+ :: A [=scroll timeline offset=] which determines the [=effective scroll
405+ offset=] in the direction specified by {{orientation}} that constitutes the
406+ beginning of the range in which the timeline is active.
419407
420408: <dfn attribute for=ScrollTimeline>end</dfn>
421- :: A scroll offset, in the direction specified by {{orientation}} , which constitutes
422- the end of the range in which the timeline is activated.
423-
424- Recognized values are defined by the following grammar:
425-
426- <blockquote>
427- <pre class="prod">auto | <<length>> | <<percentage>> </pre>
428- </blockquote>
429-
430- The meaning of each value is as follows:
431-
432- : auto
433- :: The end of {{source}} 's scroll range in {{orientation}} .
434- : <<length>>
435- :: An absolute distance along {{source}} 's scroll range in {{orientation}} .
436- : <<percentage>>
437- :: A percentage distance along {{source}} 's scroll range in {{orientation}} .
409+ :: A [=scroll timeline offset=] which determines the [=effective scroll
410+ offset=] in the direction specified by {{orientation}} that constitutes the
411+ end of the range in which the timeline is active.
438412
439413: <dfn attribute for=ScrollTimeline>timeRange</dfn>
440414:: A time duration that allows mapping between a distance scrolled, and
441415 quantities specified in time units, such as an animation's [=duration=] and
442416 [=start delay=] .
443417
444- Conceptually, {{timeRange}} represents the number of milliseconds to map to the
445- scroll range defined by {{start}} and {{end}} . As a
446- result, this value does not have a correspondence to wall-clock time.
418+ Conceptually, {{timeRange}} represents the number of milliseconds to map to
419+ the scroll range defined by {{start}} and {{end}} . As a result, this value
420+ does not have a correspondence to wall-clock time.
447421
448422 This value is used to compute the timeline's [=effective time range=] , and
449423 the mapping is then defined by mapping the scroll distance from
450424 {{start}} to {{end}} , to the [=effective time range=] .
451425
452426</div>
453427
454- ### The effective time range of a {{ScrollTimeline}} ### {#efffective-time-range-algorithm}
428+ ### Scroll Timeline Offset ### {#scroll-timeline-offset-section}
429+
430+ An <dfn>effective scroll offset</dfn> is a scroll position for a given [=scroll
431+ container=] and on a given scroll direction.
432+
433+ A <dfn>scroll timeline offset</dfn> is provided by authors and determines a
434+ [=effective scroll offset=] for the {{source}} and in the direction specified by
435+ {{orientation}} .
436+
437+ There are two types of scroll timeline offset: [=container-based offset=] , and
438+ [=element-based offset=] . To <dfn>resolve a scroll timeline offset</dfn> into an
439+ [=effective scroll offset=] , run the procedure to [=resolve a container-based
440+ offset=] or to [=resolve a element-based offset=] depending on the offset type.
441+ It is possible for a [=scroll timeline offset=] to be resolved to null.
442+
443+ The <dfn>effective start offset</dfn> is the [=effective scroll offset=] that is
444+ resolved from {{start}} . The <dfn>effective end offset</dfn> is
445+ the [=effective scroll offset=] that is resolved from {{end}} .
446+
447+ #### Container-based Offset #### {#container-based-offset-section}
448+ A <dfn>container-based offset</dfn> is a scroll timeline offset that is declared
449+ only in relation with the <a>scroll container</a> as specified by {{source}} .
450+
451+ A [=container-based offset=] is provided in the {{DOMString}} form and can have
452+ one the following three values:
453+
454+ * auto
455+ * <<length>>
456+ * <<percentage>>
457+
458+
459+ The procedure to <dfn>resolve a container-based offset</dfn> given
460+ <var> offset</var> is as follows:
461+
462+ 1. [=effective scroll offset=] is the scroll offset corresponding to the first
463+ matching condition from the following:
464+ <div class="switch">
465+
466+ : <var> offset</var> is <code> auto</code>
467+ :: Either the beginning or the ending of {{source}} 's scroll range
468+ in {{orientation}} depending on whether the offset is {{start}} or {{end}} .
469+
470+ : <var> offset</var> is a <<length>>
471+ :: The absolute distance indicated by the value along {{source}} 's scroll range
472+ in {{orientation}} .
473+
474+ : <var> offset</var> is a <<percentage>>
475+ :: The percentage distance along {{source}} 's scroll range in {{orientation}} .
476+
477+ </div>
478+
479+ Note: The scroll range of an element is the range defined by its minimum and
480+ maximum scroll offsets which are determined by it [=scrolling box=] , [=padding
481+ box=] , and [=overflow direction=] .
482+
483+ Note: It is valid to provide a length or percentage based offset such that it is
484+ outside the source's scroll range and thus not reachable e.g., '120%' .
485+
486+ #### Element-based Offset #### {#element-based-offset-section}
487+
488+ An <dfn>element-based offset</dfn> is a scroll timeline offset that is declared
489+ in terms of the intersection of the <a>scroll container</a> as specified by
490+ {{source}} and one of its descendents as specified by {{target}} .
491+
492+ An [=element-based offset=] is provided in the {{ElementBasedOffset}} form.
493+
494+ <pre class="idl">
495+ enum Edge { "start", "end" };
496+
497+ dictionary ElementBasedOffset {
498+ Element target;
499+ Edge edge = "start";
500+ };
501+ </pre>
502+
503+
504+ <div class=members>
505+
506+ : <dfn dict-member for=ElementBasedOffset>target</dfn>
507+ :: The target whose intersection with {{source}} 's [=scrolling box=] determines
508+ the concrete scroll offset.
509+
510+ : <dfn dict-member for=ElementBasedOffset>edge</dfn>
511+ :: The edge of {{source}} 's [=scrolling box=] which the target should
512+ intersect with.
513+
514+ </div>
515+
516+
517+ Issue: TODO: Add threshold value that allows authors to control how much of the
518+ target should become visible within scrollport.
519+
520+
521+ The procedure to <dfn>resolve a element-based offset</dfn> given
522+ <var> offset</var> is as follows:
523+
524+ 1. If {{source}} is null, does not currently have a [=CSS layout box=] , or if
525+ its layout box is not a [=scroll container=] , then the [=effective scroll
526+ offset=] is null and abort the following steps.
527+
528+ 1. Let <var> target</var> be <var> offset</var> 's {{target}} .
529+
530+ 1. If <var> target</var> is null, does not currently have a [=CSS layout box=] ,
531+ then the [=effective scroll offset=] is null and abort the following steps.
532+
533+ 1. If <var> target</var> 's nearest [=scroll container=] ancestor is not the
534+ {{source}} then the [=effective scroll offset=] is null and abort the
535+ following steps.
536+
537+ 1. Let <var> container box</var> be the {{source}} 's [=scrollport=] .
538+
539+ 1. Let <var> target box</var> be the result of finding the rectangular bounding
540+ box (axis-aligned in the {{source}} ’s coordinate space) of
541+ <var> target</var> 's transformed border box.
542+
543+ 1. If <var> offset</var> 's {{edge}} is ' start' then let <var> scroll offset</var>
544+ be the scroll offset at which <var> container box</var> 's start edge is flush
545+ with the <var> target box</var> 's end edge in the axis and direction
546+ determined by {{orientation}} .
547+
548+ 1. If <var> offset</var> 's {{edge}} is ' end' then let <var> scroll offset</var>
549+ be the scroll offset at which <var> container box</var> 's end edge is flush
550+ with the <var> target box</var> 's start edge in the axis and direction
551+ determined by {{orientation}} .
552+
553+ 1. Clamp the value of <var> scroll offset</var> to be within the {{source}} 's
554+ scroll range.
555+
556+ 1. The [=effective scroll offset=] is <var> scroll offset</var>
557+
558+
559+
560+ Note: The current algorithm selects the effective scroll offset such that the
561+ target is adjacent to the scrollport but not yet visible. The upcoming threshold
562+ value will allow authors to control the amount of target that needs to be
563+ visible.
564+
565+ <div class="example">
566+ Here is a basic example showing how element-based offsets can be used to declare
567+ an scroll-linked animation that occurs when an element enters the scroller
568+ scrollport and ends once it exits the scrollport.
569+
570+ <figure>
571+ <img src="img/example-element-based.svg" width="600"
572+ alt="Example usage of element-based offset.">
573+ <figcaption>
574+ Usage of element-based offsets to create enter/exit triggers.<br>
575+ The left figure shows the scroller and target being aligned at 'end' edge.<br>
576+ The right figure shows them being aligned at 'start' edge.
577+ </figcaption>
578+ </figure>
579+
580+
581+ Note that here we are expecting a typical top to bottom scrolling and thus
582+ consider the entrance to coincide when target's start edge is flushed with
583+ scrollport's <strong> end edge</strong> and viceversa for exit.
584+
585+ <pre class='lang-javascript'>
586+ if (window.matchMedia('(prefers-reduced-motion: no-preference)' ).matches) {
587+ const scrollableElement = document.querySelector('#container' );
588+ const image = document.querySelector('#image' );
589+
590+ const timeline = new ScrollTimeline({
591+ source: scrollableElement,
592+ start: {target: image, edge: 'end' },
593+ end: {target: image, edge: 'start' },
594+ });
595+
596+ const slideIn = target.animate({
597+ transform: ['translateX(0)',q 'translateX(50vw)'] ,
598+ opacity: [0, 1]
599+ }, {
600+ timeline:timeline,
601+ duration: 1000
602+ }
603+ );
604+ }
605+ </pre>
606+
607+
608+ </div>
609+
610+ ### The effective time range of a {{ScrollTimeline}} ### {#effective-time-range-algorithm}
455611
456- The <dfn>effective time range</dfn> of a {{ScrollTimeline}} is calculated as follows:
612+ The <dfn>effective time range</dfn> of a {{ScrollTimeline}} is calculated as
613+ follows:
457614
458615<div class="switch">
459616
@@ -472,29 +629,63 @@ The <dfn>effective time range</dfn> of a {{ScrollTimeline}} is calculated as fol
472629
473630</div>
474631
632+ ### The effective scroll range of a {{ScrollTimeline}} ### {#effective-scroll-range-algorithm}
633+
634+ The procedure to calculate <dfn>effective scroll range</dfn> of a
635+ {{ScrollTimeline}} is as follows:
636+
637+ 1. Run the procedure to [=resolve a scroll timeline offset=] for both {{start}}
638+ and {{end}} .
639+
640+ 1. Calculate [=effective scroll range=] as follow:
641+ <div class="switch">
642+ : If [=effective start offset=] or [=effective end offset=] is null.
643+ :: The [=effective scroll range=] is null.
644+
645+ : Otherwise
646+ :: The [=effective scroll range=] is the result of evaluating the following
647+ expression:
648+ <blockquote>
649+ <code> [=effective end offset=] - [=effective start offset=] </code>
650+ </blockquote>
651+
652+ </div>
653+
475654### The current time of a {{ScrollTimeline}} ### {#current-time-algorithm}
476655
477- The [=current time=] of a {{ScrollTimeline}} is calculated
478- as follows:
656+ The [=current time=] of a {{ScrollTimeline}} is calculated as follows:
657+
658+ 1. If {{source}} is null, does not currently have a [=CSS layout box=] , or if
659+ its layout box is not a [=scroll container=] , return an unresolved time
660+ value.
479661
480- 1. If {{source}} is null, does not currently have a [=CSS layout box=] , or
481- if its layout box is not a [=scroll container=] , return an unresolved time value .
662+ 1. Otherwise, let <var> current scroll offset </var> be the current scroll offset
663+ of {{source}} in the direction specified by {{orientation}} .
482664
483- 1. Otherwise, let <var> current scroll offset</var> be the current scroll offset of {{source}}
484- in the direction specified by {{orientation}} .
665+ 1. If [=effective scroll range=] is null, return an unresolved time value.
485666
486- 1. If <var> current scroll offset</var> is less than {{start}} , return 0.
667+ 1. If <var> current scroll offset</var> is less than [=effective start offset=] ,
668+ return 0.
487669
488- Note: TODO(<a href="https://github.com/w3c/csswg-drafts/issues/4325#issuecomment-585295758">Issue 4325</a> ): Define what the correct timeline state is based on scroll offset.
670+ Issue(4325): Define what the correct timeline state is based on scroll
671+ offset.
489672
490- 1. If <var> current scroll offset</var> is greater than or equal to {{end}} , return [=effective time range=] .
673+ 1. If <var> current scroll offset</var> is greater than or equal to [=effective
674+ end offset=] , return [=effective time range=] .
491675
4926761. Return the result of evaluating the following expression:
493677
494678 <blockquote>
495- <code> (<var> current scroll offset</var> - {{ start}} ) / ( {{end}} - {{start}} ) × [=effective time range=] </code>
679+ <code> (<var> current scroll offset</var> - [=effective start offset=] ) / [=effective scroll range=] × [=effective time range=] </code>
496680 </blockquote>
497681
682+
683+
684+ Note: To be considered active a scroll timeline requires its [=effective start
685+ offset=] and its [=effective end offset=] to be non-null. This means that for
686+ example if one uses an element-based offset whose {{target}} is not a descendant
687+ of the scroll timeline {{source}} , the timeline remains inactive.
688+
498689## The 'animation-timeline' property ## {#animation-timeline}
499690
500691A {{ScrollTimeline}} may be applied to a CSS Animation [[CSS3-ANIMATIONS]] using
0 commit comments