From fc6766d95aeb0768ec8a09253d73114090369614 Mon Sep 17 00:00:00 2001 From: fantasai Date: Fri, 29 Jul 2022 13:26:54 -0400 Subject: [PATCH] [scroll-animations-1] Rewrite scroll animations based on new declarative model. #6674 --- scroll-animations-1/Overview.bs | 1614 +++++++++---------------------- scroll-animations-1/rewrite.bs | 598 ------------ 2 files changed, 478 insertions(+), 1734 deletions(-) delete mode 100644 scroll-animations-1/rewrite.bs diff --git a/scroll-animations-1/Overview.bs b/scroll-animations-1/Overview.bs index 28d972299e8..78c49f17046 100644 --- a/scroll-animations-1/Overview.bs +++ b/scroll-animations-1/Overview.bs @@ -13,9 +13,11 @@ Abstract: Defines an API and markup for creating animations that are tied to Editor: Brian Birtles, Invited Expert, brian@birchill.co.jp, w3cid 43194 Editor: Botond Ballo, Mozilla, botond@mozilla.com Editor: Antoine Quint, Apple, graouts@apple.com, w3cid 51377 -Editor: Majid Valipour, Google, majidvp@google.com, w3cid 81464 Editor: Olga Gerchikov, Microsoft, gerchiko@microsoft.com +Editor: Elika J. Etemad / fantasai, Invited Expert, http://fantasai.inkedblade.net/contact, w3cid 35400 +Editor: Robert Flack, Google +Former Editor: Majid Valipour, Google, majidvp@google.com, w3cid 81464 Former editor: Mantaroh Yoshinaga Former editor: Stephen McGruer, Google, smcgruer@google.com Markup Shorthands: markdown yes @@ -37,1220 +39,560 @@ spec: cssom-view-1; type: dfn; # Introduction # {#intro} -This specification defines mechanisms for -[[#scroll-driven-animations|driving the progress of an animation]] based -on the scroll progress of a scroll container. + This specification defines mechanisms for + driving the progress of an animation + based on the scroll progress of a scroll container. + These scroll-driven animations + use a timeline based on scroll position, + rather than one based on clock time. + Animations are linked to such a timeline + using the CSS 'animation-timeline' property + or the Web Animations API. + + [[!WEB-ANIMATIONS-1]] + + There are two types of scroll-driven timelines: + * [=scroll progress timelines=] + * [=view progress timelines=] ## 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. + 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 this model by defining a new type of animation [=timeline=]: -a [=scroll timeline=]. + This specification extends this model by defining + a new type of animation [=timeline=]: + a [=scroll progress timeline=]. -This specification defines both programming interfaces for interacting with these -concepts, as well as CSS markup which applies these concepts to CSS Animations -[[CSS3-ANIMATIONS]]. + This specification defines both + programming interfaces for interacting with these concepts, + as well as CSS properties which apply these concepts + to CSS Animations [[CSS3-ANIMATIONS]]. -The behavior of the CSS markup is described in terms of the programming interfaces. -User agents that do not support script may still implement the CSS markup -provided it behaves as if the underlying programming interfaces were in place. + The behavior of the 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. ## 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. + 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-linked 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. + Specifically, this specification allows expressing scroll-linked 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 CSS property -definition conventions from [[!CSS2]] using the value definition -syntax 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 CSS-wide keywords as their property value. -For readability they have not been repeated explicitly. - -# Use cases # {#use-cases} - -This section is non-normative - -Note: Based on this curated -list of use cases. - -Issue(4354): These use cases need updating. - -## Scrollable picture-story show ## {#scrollable-animation-usecase} - -It is sometimes desired to use an animation to tell a story where the user -controls the progress of the animation by scrolling or some other -gesture. This may be because the animation contains a lot of textual -information which the user may wish to peruse more slowly, it may be for -accessibility considerations to accommodate users who are uncomfortable -with rapid animation, or it may simply be to allow the user to easily -return to previous parts of the story such as a story that introduces -a product where the user wishes to review previous information. - -The following (simplified) example shows two balls colliding. The -animation is controlled by scroll position allowing the user to easily -rewind and replay the interaction. - -
- Use case: The picture-story show. -
- A scrollable movie.
- The left figure shows the initial position of the balls.
- The right figure shows them after they have collided. -
-
- -Using the CSS markup: - -
-	@media (prefers-reduced-motion: no-preference) {
-		div.circle {
-			animation-timing-function: linear;
-			animation-timeline: collision-timeline;
-		}
-		#left-circle {
-			animation-name: left-circle;
-		}
-		#right-circle {
-			animation-name: right-circle;
-		}
-		#union-circle {
-			animation-name: union-circle;
-			animation-fill-mode: forwards;
-			animation-timeline: union-timeline;
-		}
-
-		@scroll-timeline collision-timeline {
-			source: selector(#container);
-			orientation: block;
-			scroll-offsets: 200px, 300px;
-		}
-
-		@scroll-timeline union-timeline {
-			source: selector(#container);
-			orientation: block;
-			scroll-offsets: 250px, 300px;
-		}
-
-		@keyframes left-circle {
-			to { transform: translate(300px) }
-		}
-		@keyframes right-circle {
-			to { transform: translate(350px) }
-		}
-		@keyframes union-circle {
-			to { opacity: 1 }
-		}
-	}
-
- -Using the programming interface, we might write this as: - -
-	if (window.matchMedia('(prefers-reduced-motion: no-preference)').matches) {
-		const scrollableElement = document.querySelector('#container');
-
-		const collisionTimeline = new ScrollTimeline({
-			source: scrollableElement,
-			scrollOffsets: [CSS.px(200), CSS.px(300)]
-		});
-
-		const left = leftCircle.animate({ transform: 'translate(300px)' });
-		left.timeline = collisionTimeline;
-
-		const right = leftCircle.animate({ transform: 'translate(350px)' });
-		right.timeline = collisionTimeline;
-
-		const union = unionCircle.animate({ opacity: 1 }, { fill: "forwards" });
-		union.timeline = new ScrollTimeline({
-			source: scrollableElement,
-			scrollOffsets: [CSS.px(250), CSS.px(300)]
-		});
-	}
-
- -## The content progress bar ## {#content-progress-bar-usecase} - -Another common example of an animation that tracks scroll position is a -progress bar that is used to indicate the reader's position in a long -article. - -
- Use case: Scroll based styling -
- Content progress bar.
- The left figure shows the initial state before scrolling.
- The right figure shows the progress bar is half-filled in since the - user has scrolled half way through the article. -
-
- -Typically, the scroll bar provides this visual indication but -applications may wish to hide the scroll bar for aesthetic or useability -reasons. - -Using the updated 'animation' shorthand that includes 'animation-timeline', -this example could be written as follows: - -
-	@media (prefers-reduced-motion: no-preference) {
-		@scroll-timeline progress-timeline {
-			source: selector(#body);
-			scroll-offsets: 0, 100%;
-		}
-
-		@keyframes progress {
-			to { width: 100%; }
-		}
-		#progress {
-			width: 0px;
-			height: 30px;
-			background: red;
-			animation: 1s linear forwards progress progress-timeline;
-		}
-	}
-
- - -If we use this API for this case, the example code will be as follow: - -
-	if (window.matchMedia('(prefers-reduced-motion: no-preference)').matches) {
-		var animation = div.animate({ width: '100%' }, { fill: "forwards" });
-		animation.timeline = new ScrollTimeline(
-			{
-				scrollOffsets: [0, CSS.percent(100)]
-			}
-		);
-	}
-
- -## Combination scroll and time-base animations ## {#combination-scroll-and-time-base-animations-usecase} - -### Photo viewer ### {#movie-show-case-usecase} - -Advisement: We are currently reworking this use case - - - - - -# Scroll-driven animations # {#scroll-driven-animations} - -## Scroll timelines ## {#scroll-timelines} - -### The {{ScrollDirection}} enumeration ### {#scrolldirection-enumeration} - -
-enum ScrollDirection {
-	"block",
-	"inline",
-	"horizontal",
-	"vertical"
-};
-
- -The {{ScrollDirection}} enumeration specifies a direction of scroll of a -scrollable element. - -
- : block - :: Selects the direction along the [=block axis=], conforming to writing mode - and directionality. - - : inline - :: Selects the direction along the [=inline axis=], confirming to writing mode - and directionality. - - : horizontal - :: Selects the physical horizontal direction (ignoring writing mode and - directionality). - - : vertical - :: Selects the physical vertical direction (ignoring writing mode and - directionality). -
- -Note: Having both logical (block/inline) and physical (vertical/horizontal) -directions allows web developers to animate both logical (e.g. -margin-inline-start) and physical (e.g. transform) properties with good -behavior under different directionalities and writing modes. - -### The {{ScrollTimeline}} interface ### {#scrolltimeline-interface} - -
-enum ScrollTimelineAutoKeyword { "auto" };
-
-typedef (CSSNumericValue or CSSKeywordish) ContainerBasedOffset;
-typedef (ContainerBasedOffset or ElementBasedOffset) ScrollTimelineOffset;
-
-dictionary ScrollTimelineOptions {
-	Element? source;
-	ScrollDirection orientation = "block";
-	sequence<ScrollTimelineOffset> scrollOffsets = [];
-};
-
-[Exposed=Window]
-interface ScrollTimeline : AnimationTimeline {
-	constructor(optional ScrollTimelineOptions options = {});
-	readonly attribute Element? source;
-	readonly attribute ScrollDirection orientation;
-	readonly attribute FrozenArray<ScrollTimelineOffset> scrollOffsets;
-};
-
- -A scroll timeline is an {{AnimationTimeline}} whose time values are -determined not by wall-clock time, but by the progress of scrolling in a -[=scroll container=]. - -The {{EffectTiming/duration}} of a scroll timeline is 100%. - -
- : ScrollTimeline(options) - :: Creates a new {{ScrollTimeline}} object using the following procedure: - - 1. Let |timeline| be a new {{ScrollTimeline}} object. - - 1. Let |source| be the result corresponding to the first matching condition - from the following: - -
- : If the `source` member of |options| is missing, - :: The {{Document/scrollingElement}} of the {{Document}} associated with the {{Window}} that is - the current global object. - - : Otherwise, - :: The `source` member of |options|. -
- - 1. Set the {{ScrollTimeline/source}} of |timeline| to |source|. - - 1. Assign the {{ScrollTimeline/orientation}} and - {{ScrollTimeline/scrollOffsets}} properties of - |timeline| to the corresponding value from |options|. -
- -
- : source - :: The scrollable element whose scrolling triggers the activation and drives - the progress of the timeline. - - : orientation - :: Determines the direction of scrolling which triggers the activation and - drives the progress of the timeline. - - : scrollOffsets - :: [=Scroll timeline offsets=] which determine the [=effective scroll - offset=]s in the direction specified by {{ScrollTimeline/orientation}} that constitute the - equally-distanced in progress intervals in which the timeline is active. - - The procedure to set the offset value with |val| as the provided - value, |pos| as the position in {{ScrollTimeline/scrollOffsets}} and |size| - as the {{ScrollTimeline/scrollOffsets}} array size has the following steps: - - 1. If |val| is a {{DOMString}}, let |val| be the result of - rectifying the keywordish value. - - 2. Set the offset value to be the result corresponding to the first - matching condition from the following: - -
- : If |val| is a {{CSSKeywordValue}} and - matches the grammar `auto` and |pos| equals to 0 or |size| - 1: - :: Return |val|. - - : If |val| is a {{CSSNumericValue}} and - matches the grammar <>: - :: Return |val|. - - : If |val| is an {{ElementBasedOffset}}: - :: Return |val|. - - : Otherwise, - :: Do not set the value and throw a {{DOMException}} with error name - {{SyntaxError}}. -
-
- -### Scroll Timeline Offset ### {#scroll-timeline-offset-section} - -An effective scroll offset is a scroll position for a given [=scroll -container=] and on a given scroll direction. - -A scroll timeline offset is provided by authors and determines a -[=effective scroll offset=] for the {{ScrollTimeline/source}} and in the direction specified by -{{ScrollTimeline/orientation}}. - -There are two types of scroll timeline offset: [=container-based offset=], and -[=element-based offset=]. To resolve a scroll timeline offset into an -[=effective scroll offset=], run the procedure to [=resolve a container-based -offset=] or to [=resolve an element-based offset=] depending on the offset type. -It is possible for a [=scroll timeline offset=] to be resolved to null. - -The effective start offset is the value of first offset in -[=effective scroll offsets=] array or null if the array is empty. - -The effective end offset is the value of last offset in -[=effective scroll offsets=] array or null if the array is empty. - -#### Container-based Offset #### {#container-based-offset-section} - -A container-based offset is a scroll timeline offset that is declared -only in relation with the scroll container as specified by {{ScrollTimeline/source}}. - -A [=container-based offset=] is provided in the {{CSSNumericValue}} or -{{CSSKeywordValue}} forms. - -
- The procedure to resolve a container-based offset given - |offset| and a flag is first (to indicate if the offset - is being inserted first into [=effective scroll offsets=]) is as follows: - - 1. If any of the following are true: - - * {{ScrollTimeline/source}} is null, or - * {{ScrollTimeline/source}} does not currently have a [=CSS layout box=], or - * {{ScrollTimeline/source}}'s layout box is not a [=scroll container=]. - - The [=effective scroll offset=] is null and abort remaining steps. - - 1. The [=effective scroll offset=] is the scroll offset corresponding to the - first matching condition from the following: - -
- : If |offset| is a {{CSSKeywordValue}} and - matches `auto`: - :: The beginning of {{ScrollTimeline/source}}'s scroll range in {{ScrollTimeline/orientation}} if - is first is true or the ending of {{ScrollTimeline/source}}'s scroll range in - {{ScrollTimeline/orientation}} otherwise. - - : If |offset| is a {{CSSNumericValue}} and - matches <>: - :: The distance indicated by the value along {{ScrollTimeline/source}}'s scroll range in - {{ScrollTimeline/orientation}} as expressed by absolute length, a percentage, or a - ''calc()'' expression that resolves to a <>. - - : Otherwise, - :: null. -
-
- -Note: The scroll range of an element is the range defined by its minimum and -maximum scroll offsets which are determined by it [=scrolling box=], [=padding -box=], and [=overflow direction=]. - -Note: Container-based scroll offsets cannot be provided as bare numbers but -should be {{CSSNumericValue}}. This way the full richness of {{CSSNumericValue}} -APIs can be used to provide the offset in percentages, various length units or -'calc()' expressions. For example `CSS.percent(50)`, `CSS.px(200)`, or -`CSS.vh(10)` are valid and represent `50%`, `200px`, and `10vh`. - -Note: It is valid to provide a length or percentage based offset such that it is -outside the source's scroll range and thus not reachable e.g., '120%'. - -#### Element-based Offset #### {#element-based-offset-section} - -An element-based offset is a scroll timeline offset that is declared -in terms of the intersection of the scroll container as specified by -{{ScrollTimeline/source}} and one of its descendants as specified by {{ElementBasedOffset/target}}. - -An [=element-based offset=] is provided in the {{ElementBasedOffset}} form. - -
-enum Edge { "start", "end" };
-
-dictionary ElementBasedOffset {
-	Element target;
-	Edge edge = "start";
-	double threshold = 0.0;
-};
-
- - -
- : target - :: The target whose intersection with {{ScrollTimeline/source}}'s [=scrolling box=] determines - the concrete scroll offset. - - : edge - :: The edge of {{ScrollTimeline/source}}'s [=scrolling box=] in the direction specified by - the {{ScrollTimeline/orientation}} which the target should intersect with. - - : threshold - :: A double in the range of [0.0, 1.0] that represent the percentage - of the target that is expected to be visible in {{ScrollTimeline/source}}'s [=scrollport=] - at the intersection offset. -
-Issue(5203): The range of the `threshold` member is not currently -checked anywhere. - -
- The procedure to resolve an element-based offset given - |offset| is as follows: - - 1. If any of the following are true: - - * {{ScrollTimeline/source}} is null, or - * {{ScrollTimeline/source}} does not currently have a [=CSS layout box=], or - * {{ScrollTimeline/source}}'s layout box is not a [=scroll container=]. - - The [=effective scroll offset=] is null and abort remaining steps. - - 1. Let |target| be |offset|'s {{ElementBasedOffset/target}}. - - 1. If any of the following are true: - - * |target| is null, or - * |target| does not currently have a [=CSS layout box=]. - - The [=effective scroll offset=] is null and abort remaining steps. - - - 1. If |target| 's nearest [=scroll container=] ancestor - is not {{ScrollTimeline/source}} - abort remaining steps - since the [=effective scroll offset=] is null. - - 1. Let |container box| be the {{ScrollTimeline/source}}'s [=scrollport=]. - - 1. Let |target box| be the result of finding - the rectangular bounding box - (axis-aligned in {{ScrollTimeline/source}}’s coordinate space) - of |target|'s transformed border box. - - 1. If |offset|'s {{ElementBasedOffset/edge}} is "start" then - let |scroll offset| - be the scroll offset at which |container box|'s start edge is flush - with the |target box|'s end edge - in the axis and direction determined by {{ScrollTimeline/orientation}}. - - 1. If |offset|'s {{ElementBasedOffset/edge}} is "end" then - let |scroll offset| - be the scroll offset at which |container box|'s end edge is flush - with the |target box|'s start edge - in the axis and direction determined by {{ScrollTimeline/orientation}}. - - 1. Let |threshold amount| be the result of evaluating the following - expression where |target dimension| is |target box|'s dimension in the axis - determined by {{ScrollTimeline/orientation}}. -
- |threshold amount| = {{ElementBasedOffset/threshold}} × |target dimension| -
- - - 1. Adjust |scroll offset| by |threshold amount| as follow: -
- - : If |offset|'s {{ElementBasedOffset/edge}} is "start", - :: |scroll offset| = |scroll offset| - |threshold amount|. - - : Otherwise (|offset|'s {{ElementBasedOffset/edge}} is "end"), - :: |scroll offset| = |scroll offset| + |threshold amount|. - -
- - 1. Clamp the value of |scroll offset| to be within the {{ScrollTimeline/source}}'s - scroll range. - - 1. The [=effective scroll offset=] is |scroll offset| -
- -
- With threshold 0.0, the algorithm selects the effective scroll offset such - that the target is adjacent to the [=scrollport=] at the given edge but not yet - visible. - The threshold value allows authors - to control the amount of target that needs to be visible in [=scrollport=]. - In particular threshold value 1.0 ensure that target is fully visible - (as long as [=scrollport=] is large enough). - -
- Example usage of element-based offset. -
- Threshold controls how much of target should be visible in [=scrollport=]. -
-
-
- -
- Here is a basic example showing how element-based offsets can be used to declare - an scroll-linked animation that occurs when an element enters the scroller - scrollport and ends once it exits the scrollport. - -
- Example usage of element-based offset. -
- Usage of element-based offsets to create enter/exit triggers.
- The left figure shows the scroller and target being aligned at "end" edge.
- The right figure shows them being aligned at "start" edge. -
-
- - - Note that here we are expecting a typical top to bottom scrolling and thus - consider the entrance to coincide when target's start edge is flushed with - scrollport's end edge and viceversa for exit. - -
-	if (window.matchMedia('(prefers-reduced-motion: no-preference)').matches) {
-		const scrollableElement = document.querySelector('#container');
-		const image = document.querySelector('#image');
-
-		const timeline = new ScrollTimeline({
-			source: scrollableElement,
-			scrollOffsets: [{target: image, edge: 'end'},
-							{target: image, edge: 'start'}],
-		});
-
-		const slideIn = target.animate({
-				transform: ['translateX(0)', 'translateX(50vw)'],
-				opacity: [0, 1]
-			}, {
-				timeline:timeline
-			}
-		);
-	}
+	This specification follows the
+	CSS property definition conventions
+	from [[!CSS2]]
+	using the value definition syntax
+	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 CSS-wide keywords as their property value.
+	For readability they have not been repeated explicitly.
+
+# Scroll Progress Timelines # {#scroll-timelines}
+
+	Scroll progress timelines
+	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.
+	If the 0% position and 100% position coincide
+	(i.e. the [=scroll container=] has no overflow to scroll),
+	the timeline is [=timeline inactive state/inactive=].
+
+	[=Scroll progress timelines=] can be referenced in 'animation-timeline'
+	anonymously using the ''scroll()'' [=functional notation=]
+	or by name (see [[#timeline-scope]])
+	after declaring them using the 'scroll-timeline' properties.
+	In the Web Animations API,
+	they can be represented anonymously by a {{ScrollTimeline}} object.
+
+## Anonymous Scroll Progress Timelines ## {#scroll-timelines-anonymous}
+
+### The ''scroll()'' notation ### {#scroll-notation}
+
+	The ''scroll()'' functional notation
+	can be used as a value of 'animation-timeline'
+	and specifies a [=scroll progress timeline=].
+	Its syntax is
+
+	
+		scroll() = scroll( <>? <>? )
+		<> = block | inline | vertical | horizontal
+		<> = root | nearest | <>
 	
- The same logic can be done in CSS markup: - -
-	@media (prefers-reduced-motion: no-preference) {
-
-		@keyframes slide-in {
-			from {
-				transform: translateX(0);
-				opacity: 0;
-			}
-
-			to {
-				transform: translateX(50vw);
-				opacity: 1;
-			}
-		}
-
-		@scroll-timeline image-in-scrollport {
-			source: selector(#container);
-			scroll-offsets: selector(#image) end, selector(#image) start;
-		}
-
-		#target {
-			animation-name: slide-in;
-			animation-timeline: image-in-scrollport;
-		}
+	By default,
+	''scroll()'' references the [=block axis=] of the nearest ancestor [=scroll container=].
+	Its arguments modify this lookup as follows:
+
+	
+
block +
+ Specifies to use the measure of progress along the + [=block axis=] of the [=scroll container=]. + (Default.) + +
inline +
+ Specifies to use the measure of progress along the + [=inline axis=] of the [=scroll container=]. + +
vertical +
+ Specifies to use the measure of progress along the + [=vertical axis=] of the [=scroll container=]. + +
horizontal +
+ Specifies to use the measure of progress along the + [=horizontal axis=] of the [=scroll container=]. + +
nearest +
+ Specifies to use the nearest ancestor [=scroll container=]. + (Default.) + +
root +
+ Specifies to use the document viewport as the [=scroll container=]. + +
<> +
+ Specifies to use the nearest ancestor [=scroll container=] + that has the specified 'container-name'. [[!CSS-CONTAIN-3]] + If none exist, the document viewport is used. +
- } +### The {{ScrollTimeline}} Interface ### {#scrolltimeline-interface} + +
+		enum ScrollAxis {
+		  "block",
+		  "inline",
+		  "horizontal",
+		  "vertical"
+		};
+
+		dictionary ScrollTimelineOptions {
+		  Element? source;
+		  ScrollAxis axis = "block";
+		};
+
+		[Exposed=Window]
+		interface ScrollTimeline : AnimationTimeline {
+		  constructor(optional ScrollTimelineOptions options = {});
+		  readonly attribute Element? source;
+		  readonly attribute ScrollAxis axis;
+		};
 	
-
- -### The effective scroll offsets of a {{ScrollTimeline}} ### {#effective-scroll-offsets-algorithm} - -
- The effective scroll offsets are calculated by the procedure to - resolve scroll timeline offsets from {{ScrollTimeline/scrollOffsets}} - as follows: - - 1. Let effective scroll offsets be an empty list of - effective scroll offsets. - 1. Let first offset be true. - 1. If {{ScrollTimeline/scrollOffsets}} is empty - 1. Run the procedure to [=resolve a scroll timeline offset=] for "auto" - with the is first flag set to first offset and - add the resulted value into effective scroll offsets. - 1. Set first offset to false. - 1. Run the procedure to [=resolve a scroll timeline offset=] for "auto" - with the is first flag set to first offset and - add the resulted value into effective scroll offsets. - 1. If {{ScrollTimeline/scrollOffsets}} has exactly one element - 1. Run the procedure to [=resolve a scroll timeline offset=] for "auto" - with the is first flag set to first offset and - add the resulted value into effective scroll offsets. - 1. Set first offset to false. - 1. For each scroll offset in the list of - {{ScrollTimeline/scrollOffsets}}, perform the following steps: - 1. Let effective offset be the result of applying the procedure - to [=resolve a scroll timeline offset=] for scroll offset - with the is first flag set to first offset. - 1. If effective offset is null, the - [=effective scroll offsets=] is empty and abort the remaining steps. - 1. Add effective offset into - effective scroll offsets. - 1. Set first offset to false. - 1. Return effective scroll offsets. -
- -### The progress of a {{ScrollTimeline}} ### {#progress-calculation-algorithm} - -
- The scroll timeline progress is calculated by applying the procedure - to calculate scroll timeline progress given |offset| as follows: - - 1. Let scroll offsets be the result of applying the procedure to - [=resolve scroll timeline offsets=] for {{ScrollTimeline/scrollOffsets}}. - 1. Let offset index correspond to the position of the last offset in - scroll offsets whose value is less than or equal to - offset and the value at the following position greater than - offsetstart offset be the offset value at position - offset index in scroll offsets. - 1. Let end offset be the value of next offset in scroll - offsets after start offset. - 1. Let size be the number of offsets in scroll offsets. - 1. Let offset weight be the result of evaluating - 1 / (size - 1). - 1. Let interval progress be the result of evaluating - (offset - start offset) / - (end offset - start offset). - 1. Return the result of evaluating - (offset index + interval progress) × - offset weight. - - Note: This procedure guarantees that given offset belongs to - scroll range within first and last offsets of scroll offsets. - This is because the case when offset falls outside of the scroll - range is handled before calling this procedure, as part of [=timeline/current time=] - calculation. - - Note: The rationale behind choosing last matching offset in the array is to - be consistent with {{findRule()}} method for finding which {{CSSKeyframeRule}} - applies in a comma separated list of overlapping keyframes. -
- -### The phase of a {{ScrollTimeline}} ### {#phase-algorithm} - -The [=timeline phase=] of a {{ScrollTimeline}} is calculated as follows: - -1. If any of the following are true: - - * {{ScrollTimeline/source}} is null, or - * {{ScrollTimeline/source}} does not currently have a [=CSS layout box=], or - * {{ScrollTimeline/source}}'s layout box is not a [=scroll container=], or - * [=effective scroll offsets=] is empty. - - The [=timeline phase=] is [=timeline/inactive phase|inactive=] and abort remaining steps. - -1. Let |current scroll offset| be the current scroll offset of - {{ScrollTimeline/source}} in the direction specified by {{ScrollTimeline/orientation}}. - -1. The [=timeline phase=] is the result corresponding to the first matching condition - from below: - -
- : If |current scroll offset| is less than [=effective start offset=]: - :: The [=timeline phase=] is [=timeline/before phase|before=] - - : If |current scroll offset| is greater than or equal to [=effective - end offset=] and [=effective end offset=] is less than the maximum - scroll offset of {{ScrollTimeline/source}} in {{ScrollTimeline/orientation}}: - - :: The [=timeline phase=] is [=timeline/after phase|after=] - - Note: In web animations, in general ranges are normally exclusive of their end - point. But there is an exception here for the scroll timeline active range as it - may in some cases be inclusive of its end. In particular if the timeline end - offset is the maximum scroll offset we include it in active range because it is - not possible for user to scroll passed this point and not including this value - in the active range would leave to animations that would not be active at the - very last scroll position. - - : Otherwise, - :: The [=timeline phase=] is [=timeline/active phase|active=]. -
-### The current time of a {{ScrollTimeline}} ### {#current-time-algorithm} + 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=]. + +
+ : source + :: The [=scroll container=] element + whose scroll position drives the progress of the timeline. + + : axis + :: The axis of scrolling + that drives the progress of the timeline. + See value definitions for <>, above. +
-The [=timeline/current time=] of a {{ScrollTimeline}} is calculated as follows: + Inherited attributes: +
+ : {{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 [=timeline inactive state|inactive=]. +
-1. If any of the following are true: + 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? + - * {{ScrollTimeline/source}} is null, or - * {{ScrollTimeline/source}} does not currently have a [=CSS layout box=], or - * {{ScrollTimeline/source}}'s layout box is not a [=scroll container=], or - * [=effective scroll offsets=] is empty. + ISSUE: Add a note about whether {{AnimationTimeline/currentTime}} + can be negative or > 100%. - The [=timeline/current time=] is an unresolved time value and abort remaining steps. +
+ : ScrollTimeline(options) + :: Creates a new {{ScrollTimeline}} object using the following procedure: -1. Let |current scroll offset| be the current scroll offset of - {{ScrollTimeline/source}} in the direction specified by {{ScrollTimeline/orientation}}. + 1. Let |timeline| be the new {{ScrollTimeline}} object. -1. The [=timeline/current time=] is the result corresponding to the first matching - condition from below: + 1. Set the {{ScrollTimeline/source}} of |timeline| to: -
- : If |current scroll offset| is less than [=effective start offset=]: - :: The [=timeline/current time=] is 0. +
+ : If the `source` member of |options| is present and not null, + :: The `source` member of |options|. - : If |current scroll offset| is greater than or equal to [=effective - end offset=]: - :: The [=timeline/current time=] is the {{EffectTiming/duration}}. + : Otherwise, + :: The {{Document/scrollingElement}} + of the {{Document}} associated + with the {{Window}} that is the current global object. +
- : Otherwise, - :: 1. Let |progress| be a result of applying - [=calculate scroll timeline progress=] procedure for current scroll offset. - 1. The [=timeline/current time=] is |progress| × {{EffectTiming/duration}} + 1. Set the {{ScrollTimeline/axis}} property of |timeline| + to the corresponding value from |options|.
-Note: To be considered active a scroll timeline requires its [=effective scroll -offsets=] to be non-empty. This means that for example if one uses an -element-based offset whose {{ElementBasedOffset/target}} is not a descendant of the scroll timeline -{{ScrollTimeline/source}}, the timeline remains inactive. - -## The ''@scroll-timeline'' at-rule ## {#scroll-timeline-at-rule} + If the {{ScrollTimeline/source}} of a {{ScrollTimeline}} + is an element whose [=principal box=] does not exist + or is not a [=scroll container=], + then the {{ScrollTimeline}} is [=timeline inactive state|inactive=]. + It is otherwise in the [=timeline active state|active=] [=timeline state=]. -[=Scroll timelines=] are specified in CSS using the @scroll-timeline -at-rule, defined as follows: + A {{ScrollTimeline}}’s {{EffectTiming/duration}} is 100%. -
-  <@scroll-timeline> = @scroll-timeline <> { <> }
+## Named Scroll Progress Timelines ## {#scroll-timelines-named}
 
-
- -An ''@scroll-timeline'' rule has a name given by the <> or <> in -its prelude. The two syntaxes are equivalent in functionality; the name is the -value of the ident or string. As normal for <>s and <>s, -the names are fully case-sensitive; two names are equal only if they are -codepoint-by-codepoint equal. The <> additionally excludes the -none keyword. + Scroll timelines can also be defined on the scroll container itself, + and then referenced by name. + See [[#timeline-scope]]. -Once specified, a scroll timeline may be associated with a CSS Animation -[[CSS3-ANIMATIONS]] by using the 'animation-timeline' property. +### Naming a Scroll Progress Timeline: the 'scroll-timeline-name' property ### {#scroll-timeline-name} -The <> inside of ''@scroll-timeline'' rule can only contain the -descriptors defined in this section. - -An ''@scroll-timeline'' rule is invalid if it occurs in a stylesheet inside of a -[=shadow tree=], and must be ignored. +
+	Name: scroll-timeline-name
+	Value: none | <>
+	Initial: none
+	Applies to: [=scroll containers=]
+	Inherited: no
+	Computed value: the specified keyword
+	Animation type: not animatable
+	
-Issue(5167): This will likely change in the future. + Specifies a name for the [=scroll progress timeline=] + associated with this [=scroll container=]. + The axis for this timeline is given by 'scroll-timeline-axis'. -### Scroll Timeline descriptors ### {#scroll-timeline-descriptors} +### Axis of a Scroll Progress Timeline: the 'scroll-timeline-axis' property ### {#scroll-timeline-axis} +
+	Name: scroll-timeline-axis
+	Value: block | inline | vertical | horizontal
+	Initial: block
+	Applies to: [=scroll containers=]
+	Inherited: no
+	Computed value: the specified keyword
+	Animation type: not animatable
+	
-
-	Name: source
-	For: @scroll-timeline
-	Value: selector( <> ) | auto | none
-	Initial: auto
-
+ Specifies an axis for the [=scroll progress timeline=] + associated with this [=scroll container=]. + The name for this timeline is given by 'scroll-timeline-name'. -'source' descriptor determines the scroll timeline's {{ScrollTimeline/source}}, -with the following values: + Values are as defined for ''scroll()''. -
- : selector() - :: The [=scroll container=] identified by the <>. +### Scroll Timeline Shorthand: the 'scroll-timeline' shorthand ### {#scroll-timeline-shorthand} - : auto - :: The {{Document/scrollingElement}} of the {{Document}} associated with the {{Window}} that is the - current global object. +
+	Name: scroll-timeline
+	Value: <<'scroll-timeline-axis'>> || <<'scroll-timeline-name'>>
+	Applies to: [=scroll containers=]
+	Inherited: no
+	Animation type: not animatable
+	
- : none - :: null. + 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 element + (the view progress subject element) + is in view within the [=scrollport=]. + View progress timelines + are segments of a [=scroll progress timeline=] + that are scoped to the scroll positions + in which the associated element’s [=principal box=] + intersects its nearest ancestor [=scrollport=]. + The startmost such scroll position represents 0% progress + and the endmost such scroll position represents 100% progress. + + [=View progress timelines=] can be referenced in 'animation-timeline' by name + (see [[#timeline-scope]]) + 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. + +## Anonymous View Progress Timelines ## {#view-timelines-anonymous} + +### The {{ViewTimeline}} Interface ### {#viewtimeline-interface} + +
+		dictionary ViewTimelineOptions {
+		  Element subject;
+		  ScrollAxis axis = "block";
+		};
+
+		[Exposed=Window]
+		interface ViewTimeline : ScrollTimeline {
+		  constructor(optional ViewTimelineOptions options = {});
+		  readonly attribute Element subject;
+		  readonly attribute CSSNumericValue startOffset;
+		  readonly attribute CSSNumericValue endOffset;
+		};
+	
- Issue: What does "null." mean? -
+ 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=]. + +
+ : subject + :: The element whose [=principal box=]’s visibility in the [=scrollport=] + defines the progress of the timeline. + + : startOffset + :: 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 [=timeline inactive state|inactive=]. + + : endOffset + :: 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 [=timeline inactive state|inactive=]. +
-Issue(4338): Consider choosing animation target's nearest scrollable ancestor -instead of document's scrolling Element for `auto`. + Note: The value of {{ViewTimeline/startOffset}} can be greater than {{ViewTimeline/endOffset}}, + for example in the [=horizontal axis=] in a right-to-left (''rtl'') [=writing mode=]. -
-  Name: orientation
-  For: @scroll-timeline
-  Value: auto | block | inline | horizontal | vertical
-  Initial: auto
-
+ ISSUE: This makes the offsets compatible with the way scrollLeft and scrollTop work, + which go negative from zero in RTL scroll containers, + is this how we want it to work here? -'orientation' descriptor determines the scroll timeline's {{ScrollTimeline/orientation}}. + Inherited attributes: -Issue: Define these values. +
+ : {{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. -
-  Name: scroll-offsets
-  For: @scroll-timeline
-  Value: none | <>#
-  Initial: none
-
+ : {{ScrollTimeline/axis}} (inherited from {{ScrollTimeline}}) + :: Specifies the axis of scrolling + that drives the progress of the timeline. + See <>, above. -'scroll-offsets' descriptor determines the scroll timeline's {{ScrollTimeline/scrollOffsets}}. + : {{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 [=timeline inactive state|inactive=]. +
-[=Scroll timeline offsets=] in CSS are represented by the -<> type: +
+ : ViewTimeline(options) + :: Creates a new {{ViewTimeline}} object using the following procedure: -
-	<scroll-timeline-offset> = auto | <> | <>
-	<element-offset> = selector( <> ) [<> || <>]?
-	<element-offset-edge> = start | end
-
+ 1. Let |timeline| be the new {{ViewTimeline}} object. -The offset type depends on the value of <> per -following: - -
- : If value is "auto" or of type <> - :: The [=scroll timeline offset=] is a [=container-based offset=] with the same - value. - - : If value is of type <> - :: The [=scroll timeline offset=] is an [=element-based offset=] with the - following member values: - * {{ElementBasedOffset/target}} is the element identified by - <>. - * {{ElementBasedOffset/edge}} is the optional value of - <>. If not provided it defaults to "start". - * {{ElementBasedOffset/threshold}} is the optional value <>. If - not provided it defaults to 0. -
- -### The CSSScrollTimelineRule Interface ### {#the-css-scroll-timeline-rule-interface} - -
-[Exposed=Window]
-interface CSSScrollTimelineRule : CSSRule {
-	readonly attribute CSSOMString name;
-	readonly attribute CSSOMString source;
-	readonly attribute CSSOMString orientation;
-	readonly attribute CSSOMString scrollOffsets;
-};
-
+ 1. Set the {{ViewTimeline/subject}} and {{ScrollTimeline/axis}} properties of |timeline| + to the corresponding values from |options|. -
-
name -
- The name associated with the ''@scroll-timeline'' rule. - -
source -
- The 'source' descriptor associated with the ''@scroll-timeline'', or "auto" - if not specified. - -
orientation -
- The 'orientation' descriptor associated with the ''@scroll-timeline'', or "auto" if not specified. - -
scrollOffsets -
- The 'scroll-offsets' descriptor associated with the ''@scroll-timeline'', or "none" if not specified. -
- -
- To serialize a CSSScrollTimelineRule, - return the concatenation of the following: - - 1. The string "@scroll-timeline" followed by a SPACE (U+0020). - 1. The result of performing serialize an identifier on the rule's - {{CSSScrollTimelineRule/name}}, followed by a SPACE (U+0020). - 1. A single LEFT CURLY BRACKET (U+007B), followed by a SPACE (U+0020). - 1. If the 'source' descriptor is missing, the empty string. - Otherwise, the concatenation of the following: - 1. The string "source:", followed by a SPACE (U+0020). - 1. One of the following, - depending on the value of the 'source' descriptor: -
- : an identifier - :: The result of performing serialize an identifier - on that identifier. - : selector(<id-selector>) - :: The result of performing - serialize a selector() function. -
- 1. A single SEMICOLON (U+003B), followed by a SPACE (U+0020). - 1. If the 'orientation' descriptor is missing, the empty string. - Otherwise, the concatenation of the following: - 1. The string "orientation:", - followed by a SPACE (U+0020). - 1. The result of performing serialize an identifier - on the value of the 'orientation' descriptor, - followed by a SEMICOLON (U+003B), - followed by a SPACE (U+0020). - 1. If the 'scroll-offsets' descriptor is missing, the empty string. - Otherwise, the concatenation of the following: - 1. The string "scrollOffsets:", - followed by a SPACE (U+0020), - followed by a LEFT SQUARE BRACKET (U+005B). - 1. For each value in the list for the rule's 'scroll-offsets' - descriptor: - 1. The result of performing - serialize a scroll timeline offset on the value. - 1. If not the last value, - A COMMA (U+002C), followed by a SPACE (U+0020). - 1. A RIGHT SQUARE BRACKET (U+005D), - followed by a SEMICOLON (U+003B), - followed by a SPACE (U+0020). - 1. A single RIGHT CURLY BRACKET (U+007D). -
- -
- To serialize a scroll timeline offset, - return one of the following, - depending on the value type: - -
- : an identifier - : <> - :: The result of performing serialize a CSS component value - on that value. - : <> - :: The concatenation of the following: - 1. The result of performing serialize a selector() function - on the selector() function associated with the element offset. - 2. If the offset has an associated {{ElementBasedOffset/edge}}, - a single SPACE (U+0020), - followed by the result of serialize an identifier - on the value of "edge". - Otherwise, the empty string. - 3. If the offset has an associated {{ElementBasedOffset/threshold}}, - a single SPACE (U+0020), - followed by the result of serialize a CSS component value - on the value of "threshold". - Otherwise, the empty string. + 1. Set the {{ScrollTimeline/source}} of |timeline| + to the {{ViewTimeline/subject}}’s + nearest ancestor [=scroll container=] element.
-
+ If the {{ScrollTimeline/source}} or {{ViewTimeline/subject}} of a {{ViewTimeline}} + is an element whose [=principal box=] does not exist, + then the {{ViewTimeline}} is [=timeline inactive state|inactive=]. + It is otherwise in the [=timeline active state|active=] [=timeline state=]. -
- To serialize a selector() function, - return the concatenation of the following: + ISSUE: Figure out how to incorporate fit/inset abilities. - 1. The string "selector", - followed by LEFT PARENTHESIS (U+0028). - 2. The result of performing serialize a selector - on the selector() function's argument. - 3. A single RIGHT PARENTHESIS (U+0029). -
+## Named View Progress Timelines ## {#view-timelines-named} -## Examples ## {#timeline-examples} + View timelines can also be defined declaratively + and then referenced by name. + See [[#timeline-scope]]. -
- Draw a reading progress bar along the top of the page as the user scrolls. +### Naming a View Progress Timeline: the 'view-timeline-name' property ### {#view-timeline-name} -
-		#progress {
-			position: fixed;
-			top: 0;
-			width: 0;
-			height: 2px;
-			background-color: red;
-		}
-	
-
-		if (window.matchMedia('(prefers-reduced-motion: no-preference)').matches) {
-			let progress = document.getElementById("progress");
-			let effect = new KeyframeEffect(
-				progress,
-				[
-					{ width: "0vw" },
-					{ width: "100vw" }
-				],
-				{
-					easing: "linear",
-					fill: "forwards"
-				});
-			let timeline = new ScrollTimeline({
-				source: document.documentElement,
-				orientation: "vertical",
-			});
-			let animation = new Animation(effect, timeline);
-			animation.play();
-		}
-	
-
- -
- The same thing with CSS, using 'animation-timeline'. - -
-		@media (prefers-reduced-motion: no-preference) {
-
-			@scroll-timeline progress {
-				/* Assume the HTML element has id 'root' */
-				source: selector(#root);
-				orientation: vertical;
-			}
-
-			@keyframes progress {
-				from {
-					width: 0vw;
-				}
-				to {
-					width: 100vw;
-				}
-			}
-
-			#progress {
-				position: fixed;
-				top: 0;
-				width: 0;
-				height: 2px;
-				background-color: red;
-				/* This name is used to select both the keyframes and the
-					 scroll-timeline at-rules. */
-				animation-name: progress;
-				animation-fill-mode: forwards;
-				animation-timing-function: linear;
-			}
-
-		}
+	
+	Name: view-timeline-name
+	Value: none | <>#
+	Initial: none
+	Applies to: all elements
+	Inherited: no
+	Computed value: the keyword ''view-timeline-name/none'' or a list of <>s
+	Animation type: not animatable
 	
-
-# Avoiding cycles with layout # {#avoiding-cycles} - -The ability for scrolling to drive the progress of an animation, gives rise to -the possibility of layout cycles, 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 {{ScrollTimeline}} are -sampled once per frame, after scrolling in response to input events has taken -place, but before {{requestAnimationFrame()}} callbacks are run. If the sampling -of such an animation causes a change to a scroll offset, the animation will not -be re-sampled to reflect the new offset until the next frame. - -The implication of this is that in some situations, in a given frame, the -rendered scroll offset of a scroll container may not be consistent with the state -of an animation driven by scrolling that scroll container. However, this will -only occur in situations where the animation's effect changes the scroll offset -of that same scroll container (in other words, in situations where the animation's -author is asking for trouble). In normal situations, including - importantly - -when scrolling happens in response to input events, the rendered scroll offset -and the state of scroll-driven animations will be consistent in each frame. - -User agents that composite frames asynchronously with respect to layout and/or -script may, at their discretion, sample scroll-driven animations once per -composited frame, rather than (or in addition to) once per full layout -cycle. Again, if sampling such an animation causes a change to a scroll offset, -the animation will not be re-sampled to reflect the new offset until the next -frame. - -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. - - -

Appendix A. Considerations for Security and Privacy

+ Specifies names for any [=view progress timelines=] + associated with this element’s [=principal box=]. -This appendix is informative. + Note: The number of names listed here + determines the number of [=view progress timelines=] + associated with this element. -There are no known security or privacy impacts of this feature. +### Axis of a View Progress Timeline: the 'view-timeline-axis' property ### {#view-timeline-axis} -The W3C TAG is developing a -Self-Review Questionnaire: Security and Privacy -for editors of specifications to informatively answer. - -Per the Questions to Consider - -
    -
  1. Does this specification deal with personally-identifiable information? -

    No. +

    +	Name: view-timeline-axis
    +	Value: [ block | inline | vertical | horizontal ]#
    +	Initial: block
    +	Applies to: all elements
    +	Inherited: no
    +	Computed value: a list of the keywords specified
    +	Animation type: not animatable
    +	
    -
  2. Does this specification deal with high-value data? -

    No. + Specifies an axis for each named [=view progress timeline=] + associated with this [=scroll container=]. + + If 'view-timeline-name' has more names than 'view-timeline-axis' has specified axes, + the excess timelines use the last 'view-timeline-axis' value. + If 'view-timeline-name' has fewer names than 'view-timeline-axis' has specified axes, + the used 'view-timeline-axis' list is truncated. + +### Inset of a View Progress Timeline: the 'view-timeline-inset' property ### {#view-timeline-inset} + +

    +	Name: view-timeline-inset
    +	Value: [ auto | <> ]{1,4}
    +	Initial: 0
    +	Applies to: all elements
    +	Inherited: no
    +	Percentages: relative to the corresponding dimension of the relevant scrollport
    +	Computed value: per side, the keyword ''view-timeline-inset/auto'' or a computed <> value
    +	Animation type: by computed value type
    +	
    -
  3. Does this specification introduce new state for an origin that persists across browsing sessions? -

    No. + Specifies an inset (positive) or outset (negative) adjustment of the [=scrollport=] + when determining whether the box is in view + when setting the bounds of a [=view progress timeline=]. + The resulting rectangle is the view progress rectangle. -

  4. Does this specification expose persistent, cross-origin state to the web? -

    No. +

    +
    auto +
    + Indicates to use the value of 'scroll-padding'. -
  5. Does this specification expose any other data to an origin that it doesn’t currently have access to? -

    No. +

    <> +
    + Like 'scroll-padding', + defines an inward offset from the corresponding edge of the scrollport. +
  6. -
  7. Does this specification enable new script execution/loading mechanisms? -

    No. + The 'view-timeline-inset' property assigns its values to each side + exactly as the 'margin' property does. -

  8. Does this specification allow an origin access to a user’s location? -

    No. + ISSUE: Should the initial value be zero or auto? -

  9. Does this specification allow an origin access to sensors on a user’s device? -

    No. + ISSUE: Do we need all the longhands? Seems like overkill... -

  10. Does this specification allow an origin access to aspects of a user’s local computing environment? -

    No. +### View Timeline Shorthand: the 'view-timeline' shorthand ### {#view-timeline-shorthand} -

  11. Does this specification allow an origin access to other devices? -

    No. +

    +	Name: view-timeline
    +	Value: [ <<'view-timeline-name'>> || <<'view-timeline-axis'>> ]#
    +	Applies to: all elements
    +	
    -
  12. Does this specification allow an origin some measure of control over a user agent’s native UI? -

    No. + This property is a [=shorthand=] for setting + 'view-timeline-name' and 'view-timeline-axis' + in a single declaration. + It does not set 'view-timeline-inset'. -

  13. Does this specification expose temporary identifiers to the web? -

    No. + ISSUE: Should it reset 'view-timeline-inset' also? -

  14. Does this specification distinguish between behavior in first-party and third-party contexts? -

    No. +# Named Timeline Scoping # {#timeline-scope} -

  15. How should this specification work in the context of a user agent’s "incognito" mode? -

    No differently. The website should not be able to determine that the user is - in an "incognito" mode using scroll-linked animations. + A named [=scroll progress timeline=] or [=view progress timeline=] + is referenceable in 'animation-timeline' by: + * the declaring element itself + * that element’s descendants + * that element’s following siblings and their descendants -

  16. Does this specification persist data to a user’s local device? -

    No. + If multiple elements have declared the same timeline name, + the matching timeline is the one declared + on the nearest element in tree order, + which considers siblings closer than parents. + In case of a name conflict on the same element, + [=scroll progress timelines=] take precedence over [=view progress timelines=]. -

  17. Does this specification have a "Security Considerations" and "Privacy Considerations" section? -

    Yes. + ISSUE: Do we want to expand this scope to preceding siblings and/or distant cousins? -

  18. Does this specification allow downgrading default security characteristics? -

    No. -

+# Avoiding cycles with layout # {#avoiding-cycles} + The ability for scrolling to drive the progress of an animation, + gives rise to the possibility of layout cycles, + 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=] are sampled once per frame, + after scrolling in response to input events has taken place, + but before {{requestAnimationFrame()}} callbacks are run. + If the sampling of such an animation causes a change to a scroll offset, + the animation will not be re-sampled to reflect the new offset + until the next frame. + + The implication of this is that in some situations, in a given frame, + the rendered scroll offset of a scroll container might not be consistent + with the state of an animation driven by scrolling that scroll container. + However, this will only occur in situations where the animation's effect + changes the scroll offset of that same scroll container + (in other words, in situations where the animation's author is asking for trouble). + In normal situations, including—importantly-- + when scrolling happens in response to input events, + the rendered scroll offset and the state of scroll-driven animations + will be consistent in each frame. + + User agents that composite frames asynchronously + with respect to layout and/or script + may, at their discretion, sample scroll-driven animations + once per composited frame, + rather than (or in addition to) once per full layout cycle. + Again, if sampling such an animation causes a change to a scroll offset, + the animation will not be re-sampled to reflect the new offset + until the next frame. + + 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. diff --git a/scroll-animations-1/rewrite.bs b/scroll-animations-1/rewrite.bs deleted file mode 100644 index 78c49f17046..00000000000 --- a/scroll-animations-1/rewrite.bs +++ /dev/null @@ -1,598 +0,0 @@ - -
-urlPrefix: https://html.spec.whatwg.org/multipage/browsers.html#concept-document-window; type: dfn; spec: html
-	text: document associated with a window; url: concept-document-window
-
- - - - -# Introduction # {#intro} - - This specification defines mechanisms for - driving the progress of an animation - based on the scroll progress of a scroll container. - These scroll-driven animations - use a timeline based on scroll position, - rather than one based on clock time. - Animations are linked to such a timeline - using the CSS 'animation-timeline' property - or the Web Animations API. - - [[!WEB-ANIMATIONS-1]] - - There are two types of scroll-driven timelines: - * [=scroll progress timelines=] - * [=view progress timelines=] - -## 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 this model by defining - a new type of animation [=timeline=]: - a [=scroll progress timeline=]. - - This specification defines both - programming interfaces for interacting with these concepts, - as well as CSS properties which apply these concepts - to CSS Animations [[CSS3-ANIMATIONS]]. - - The behavior of the 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. - -## 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-linked 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 - CSS property definition conventions - from [[!CSS2]] - using the value definition syntax - 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 CSS-wide keywords as their property value. - For readability they have not been repeated explicitly. - -# Scroll Progress Timelines # {#scroll-timelines} - - Scroll progress timelines - 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. - If the 0% position and 100% position coincide - (i.e. the [=scroll container=] has no overflow to scroll), - the timeline is [=timeline inactive state/inactive=]. - - [=Scroll progress timelines=] can be referenced in 'animation-timeline' - anonymously using the ''scroll()'' [=functional notation=] - or by name (see [[#timeline-scope]]) - after declaring them using the 'scroll-timeline' properties. - In the Web Animations API, - they can be represented anonymously by a {{ScrollTimeline}} object. - -## Anonymous Scroll Progress Timelines ## {#scroll-timelines-anonymous} - -### The ''scroll()'' notation ### {#scroll-notation} - - The ''scroll()'' functional notation - can be used as a value of 'animation-timeline' - and specifies a [=scroll progress timeline=]. - Its syntax is - -
-		scroll() = scroll( <>? <>? )
-		<> = block | inline | vertical | horizontal
-		<> = root | nearest | <>
-	
- - By default, - ''scroll()'' references the [=block axis=] of the nearest ancestor [=scroll container=]. - Its arguments modify this lookup as follows: - -
-
block -
- Specifies to use the measure of progress along the - [=block axis=] of the [=scroll container=]. - (Default.) - -
inline -
- Specifies to use the measure of progress along the - [=inline axis=] of the [=scroll container=]. - -
vertical -
- Specifies to use the measure of progress along the - [=vertical axis=] of the [=scroll container=]. - -
horizontal -
- Specifies to use the measure of progress along the - [=horizontal axis=] of the [=scroll container=]. - -
nearest -
- Specifies to use the nearest ancestor [=scroll container=]. - (Default.) - -
root -
- Specifies to use the document viewport as the [=scroll container=]. - -
<> -
- Specifies to use the nearest ancestor [=scroll container=] - that has the specified 'container-name'. [[!CSS-CONTAIN-3]] - If none exist, the document viewport is used. -
- -### The {{ScrollTimeline}} Interface ### {#scrolltimeline-interface} - -
-		enum ScrollAxis {
-		  "block",
-		  "inline",
-		  "horizontal",
-		  "vertical"
-		};
-
-		dictionary ScrollTimelineOptions {
-		  Element? source;
-		  ScrollAxis axis = "block";
-		};
-
-		[Exposed=Window]
-		interface ScrollTimeline : AnimationTimeline {
-		  constructor(optional ScrollTimelineOptions options = {});
-		  readonly attribute Element? source;
-		  readonly attribute ScrollAxis axis;
-		};
-	
- - 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=]. - -
- : source - :: The [=scroll container=] element - whose scroll position drives the progress of the timeline. - - : axis - :: The axis of scrolling - that drives the progress of the timeline. - See value definitions for <>, above. -
- - Inherited attributes: -
- : {{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 [=timeline inactive state|inactive=]. -
- - 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? - - - ISSUE: Add a note about whether {{AnimationTimeline/currentTime}} - can be negative or > 100%. - -
- : ScrollTimeline(options) - :: 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: - -
- : If the `source` member of |options| is present and not null, - :: The `source` member of |options|. - - : Otherwise, - :: The {{Document/scrollingElement}} - of the {{Document}} associated - with the {{Window}} that is the current global object. -
- - 1. Set the {{ScrollTimeline/axis}} property of |timeline| - to the corresponding value from |options|. -
- - If the {{ScrollTimeline/source}} of a {{ScrollTimeline}} - is an element whose [=principal box=] does not exist - or is not a [=scroll container=], - then the {{ScrollTimeline}} is [=timeline inactive state|inactive=]. - It is otherwise in the [=timeline active state|active=] [=timeline state=]. - - A {{ScrollTimeline}}’s {{EffectTiming/duration}} is 100%. - -## Named Scroll Progress Timelines ## {#scroll-timelines-named} - - Scroll timelines can also be defined on the scroll container itself, - and then referenced by name. - See [[#timeline-scope]]. - -### Naming a Scroll Progress Timeline: the 'scroll-timeline-name' property ### {#scroll-timeline-name} - -
-	Name: scroll-timeline-name
-	Value: none | <>
-	Initial: none
-	Applies to: [=scroll containers=]
-	Inherited: no
-	Computed value: the specified keyword
-	Animation type: not animatable
-	
- - Specifies a name for the [=scroll progress timeline=] - associated with this [=scroll container=]. - The axis for this timeline is given by 'scroll-timeline-axis'. - -### Axis of a Scroll Progress Timeline: the 'scroll-timeline-axis' property ### {#scroll-timeline-axis} - -
-	Name: scroll-timeline-axis
-	Value: block | inline | vertical | horizontal
-	Initial: block
-	Applies to: [=scroll containers=]
-	Inherited: no
-	Computed value: the specified keyword
-	Animation type: not animatable
-	
- - Specifies an axis for the [=scroll progress timeline=] - associated with this [=scroll container=]. - The name for this timeline is given by 'scroll-timeline-name'. - - Values are as defined for ''scroll()''. - -### Scroll Timeline Shorthand: the 'scroll-timeline' shorthand ### {#scroll-timeline-shorthand} - -
-	Name: scroll-timeline
-	Value: <<'scroll-timeline-axis'>> || <<'scroll-timeline-name'>>
-	Applies to: [=scroll containers=]
-	Inherited: no
-	Animation type: not animatable
-	
- - 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 element - (the view progress subject element) - is in view within the [=scrollport=]. - View progress timelines - are segments of a [=scroll progress timeline=] - that are scoped to the scroll positions - in which the associated element’s [=principal box=] - intersects its nearest ancestor [=scrollport=]. - The startmost such scroll position represents 0% progress - and the endmost such scroll position represents 100% progress. - - [=View progress timelines=] can be referenced in 'animation-timeline' by name - (see [[#timeline-scope]]) - 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. - -## Anonymous View Progress Timelines ## {#view-timelines-anonymous} - -### The {{ViewTimeline}} Interface ### {#viewtimeline-interface} - -
-		dictionary ViewTimelineOptions {
-		  Element subject;
-		  ScrollAxis axis = "block";
-		};
-
-		[Exposed=Window]
-		interface ViewTimeline : ScrollTimeline {
-		  constructor(optional ViewTimelineOptions options = {});
-		  readonly attribute Element subject;
-		  readonly attribute CSSNumericValue startOffset;
-		  readonly attribute CSSNumericValue endOffset;
-		};
-	
- - 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=]. - -
- : subject - :: The element whose [=principal box=]’s visibility in the [=scrollport=] - defines the progress of the timeline. - - : startOffset - :: 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 [=timeline inactive state|inactive=]. - - : endOffset - :: 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 [=timeline inactive state|inactive=]. -
- - Note: The value of {{ViewTimeline/startOffset}} can be greater than {{ViewTimeline/endOffset}}, - for example in the [=horizontal axis=] in a right-to-left (''rtl'') [=writing mode=]. - - ISSUE: This makes the offsets compatible with the way scrollLeft and scrollTop work, - which go negative from zero in RTL scroll containers, - is this how we want it to work here? - - Inherited attributes: - -
- : {{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 <>, 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 [=timeline inactive state|inactive=]. -
- -
- : ViewTimeline(options) - :: 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. -
- - If the {{ScrollTimeline/source}} or {{ViewTimeline/subject}} of a {{ViewTimeline}} - is an element whose [=principal box=] does not exist, - then the {{ViewTimeline}} is [=timeline inactive state|inactive=]. - It is otherwise in the [=timeline active state|active=] [=timeline state=]. - - ISSUE: Figure out how to incorporate fit/inset abilities. - -## Named View Progress Timelines ## {#view-timelines-named} - - View timelines can also be defined declaratively - and then referenced by name. - See [[#timeline-scope]]. - -### Naming a View Progress Timeline: the 'view-timeline-name' property ### {#view-timeline-name} - -
-	Name: view-timeline-name
-	Value: none | <>#
-	Initial: none
-	Applies to: all elements
-	Inherited: no
-	Computed value: the keyword ''view-timeline-name/none'' or a list of <>s
-	Animation type: not animatable
-	
- - Specifies names for any [=view progress timelines=] - associated with this element’s [=principal box=]. - - Note: The number of names listed here - determines the number of [=view progress timelines=] - associated with this element. - -### Axis of a View Progress Timeline: the 'view-timeline-axis' property ### {#view-timeline-axis} - -
-	Name: view-timeline-axis
-	Value: [ block | inline | vertical | horizontal ]#
-	Initial: block
-	Applies to: all elements
-	Inherited: no
-	Computed value: a list of the keywords specified
-	Animation type: not animatable
-	
- - Specifies an axis for each named [=view progress timeline=] - associated with this [=scroll container=]. - - If 'view-timeline-name' has more names than 'view-timeline-axis' has specified axes, - the excess timelines use the last 'view-timeline-axis' value. - If 'view-timeline-name' has fewer names than 'view-timeline-axis' has specified axes, - the used 'view-timeline-axis' list is truncated. - -### Inset of a View Progress Timeline: the 'view-timeline-inset' property ### {#view-timeline-inset} - -
-	Name: view-timeline-inset
-	Value: [ auto | <> ]{1,4}
-	Initial: 0
-	Applies to: all elements
-	Inherited: no
-	Percentages: relative to the corresponding dimension of the relevant scrollport
-	Computed value: per side, the keyword ''view-timeline-inset/auto'' or a computed <> value
-	Animation type: by computed value type
-	
- - Specifies an inset (positive) or outset (negative) adjustment of the [=scrollport=] - when determining whether the box is in view - when setting the bounds of a [=view progress timeline=]. - The resulting rectangle is the view progress rectangle. - -
-
auto -
- Indicates to use the value of 'scroll-padding'. - -
<> -
- Like 'scroll-padding', - defines an inward offset from the corresponding edge of the scrollport. -
- - The 'view-timeline-inset' property assigns its values to each side - exactly as the 'margin' property does. - - ISSUE: Should the initial value be zero or auto? - - ISSUE: Do we need all the longhands? Seems like overkill... - -### View Timeline Shorthand: the 'view-timeline' shorthand ### {#view-timeline-shorthand} - -
-	Name: view-timeline
-	Value: [ <<'view-timeline-name'>> || <<'view-timeline-axis'>> ]#
-	Applies to: all elements
-	
- - This property is a [=shorthand=] for setting - 'view-timeline-name' and 'view-timeline-axis' - in a single declaration. - It does not set 'view-timeline-inset'. - - ISSUE: Should it reset 'view-timeline-inset' also? - -# Named Timeline Scoping # {#timeline-scope} - - A named [=scroll progress timeline=] or [=view progress timeline=] - is referenceable in 'animation-timeline' by: - * the declaring element itself - * that element’s descendants - * that element’s following siblings and their descendants - - If multiple elements have declared the same timeline name, - the matching timeline is the one declared - on the nearest element in tree order, - which considers siblings closer than parents. - In case of a name conflict on the same element, - [=scroll progress timelines=] take precedence over [=view progress timelines=]. - - ISSUE: Do we want to expand this scope to preceding siblings and/or distant cousins? - -# Avoiding cycles with layout # {#avoiding-cycles} - - The ability for scrolling to drive the progress of an animation, - gives rise to the possibility of layout cycles, - 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=] are sampled once per frame, - after scrolling in response to input events has taken place, - but before {{requestAnimationFrame()}} callbacks are run. - If the sampling of such an animation causes a change to a scroll offset, - the animation will not be re-sampled to reflect the new offset - until the next frame. - - The implication of this is that in some situations, in a given frame, - the rendered scroll offset of a scroll container might not be consistent - with the state of an animation driven by scrolling that scroll container. - However, this will only occur in situations where the animation's effect - changes the scroll offset of that same scroll container - (in other words, in situations where the animation's author is asking for trouble). - In normal situations, including—importantly-- - when scrolling happens in response to input events, - the rendered scroll offset and the state of scroll-driven animations - will be consistent in each frame. - - User agents that composite frames asynchronously - with respect to layout and/or script - may, at their discretion, sample scroll-driven animations - once per composited frame, - rather than (or in addition to) once per full layout cycle. - Again, if sampling such an animation causes a change to a scroll offset, - the animation will not be re-sampled to reflect the new offset - until the next frame. - - 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.