Scroll-linked Animations

Editor’s Draft,

Specification Metadata
This version:
https://drafts.csswg.org/scroll-animations-1/
Issue Tracking:
Inline In Spec
GitHub Issues
Editors:
(Invited Expert)
(Mozilla)
(Apple)
(Google)
(Microsoft)
Former Editors:
Mantaroh Yoshinaga
(Google)
Suggest an Edit for this Spec:
GitHub Editor

Abstract

Defines an API and markup for creating animations that are tied to the scroll offset of a scroll container.

CSS is a language for describing the rendering of structured documents (such as HTML and XML) on screen, on paper, etc.

Status of this document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.

This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.

Please send feedback by filing issues in GitHub (preferred), including the spec code “scroll-animations-1” in the title, like this: “[scroll-animations-1] …summary of comment…”. All issues and comments are archived. Alternately, feedback can be sent to the (archived) public mailing list www-style@w3.org.

This document is governed by the 15 September 2020 W3C Process Document.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

1. Introduction

This specification defines mechanisms for driving the progress of an animation based on the scroll progress of a scroll container.

1.1. Relationship to other specifications

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 defines both programming interfaces for interacting with these concepts, as well as CSS markup which applies 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.

1.2. Relationship to asynchronous 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.

1.3. Value Definitions

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.

2. Use cases

This section is non-normative

Note: Based on this curated list of use cases.

These use cases need updating. <https://github.com/w3c/csswg-drafts/issues/4354>

2.1. Scrollable picture-story show

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-duration: 1s;
    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;
    start:  200px;
    end: 300px;
  }

  @scroll-timeline union-timeline {
    source: selector(#container);
    orientation: block;
    start:  250px;
    end: 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,
    start: CSS.px(200),
    end: CSS.px(300)
  });

  const left = leftCircle.animate({ transform: 'translate(300px)' }, 1000);
  left.timeline = collisionTimeline;

  const right = leftCircle.animate({ transform: 'translate(350px)' }, 1000);
  right.timeline = collisionTimeline;

  const union = unionCircle.animate({ opacity: 1 }, { duration: 1000, fill: "forwards" });
  union.timeline = new ScrollTimeline({
    source: scrollableElement,
    start: CSS.px(250),
    end: CSS.px(300)
  });
}

2.2. The content progress bar

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);
    start: 0;
    end: 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%' }, { duration: 1000, fill: "forwards" });
  animation.timeline = new ScrollTimeline(
    {
      start: 0,
      end: CSS.percent(100)
    }
  );
}

2.3. Combination scroll and time-base animations

2.3.1. Photo viewer

We are currently reworking this use case

3. Scroll-driven animations

3.1. Scroll timelines

3.1.1. The 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.

3.1.2. The ScrollTimeline interface

enum ScrollTimelineAutoKeyword { "auto" };

typedef (CSSNumericValue or CSSKeywordish) ContainerBasedOffset;
typedef (ContainerBasedOffset or ElementBasedOffset) ScrollTimelineOffset;

dictionary ScrollTimelineOptions {
  Element? source = null;
  ScrollDirection orientation = "block";
  ScrollTimelineOffset start = "auto";
  ScrollTimelineOffset end = "auto";
  (double or ScrollTimelineAutoKeyword) timeRange = "auto";
};

[Exposed=Window]
interface ScrollTimeline : AnimationTimeline {
  constructor(optional ScrollTimelineOptions options = {});
  readonly attribute Element? source;
  readonly attribute ScrollDirection orientation;
  readonly attribute ScrollTimelineOffset start;
  readonly attribute ScrollTimelineOffset end;
  readonly attribute (double or ScrollTimelineAutoKeyword) timeRange;
};

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.

ScrollTimeline(options)

Creates a new ScrollTimeline object using the following procedure:

  1. Let timeline be a new ScrollTimeline object.

  2. Let source be the result corresponding to the first matching condition from the following:

    If the source member of options is missing,

    The scrollingElement of the Document associated with the Window that is the current global object.

    Otherwise,

    The source member of options.

  3. Set the source of timeline to source.

  4. Assign the orientation, start, end, and timeRange properties of timeline to the corresponding value from options.

source, of type Element, readonly, nullable

The scrollable element whose scrolling triggers the activation and drives the progress of the timeline.

orientation, of type ScrollDirection, readonly

Determines the direction of scrolling which triggers the activation and drives the progress of the timeline.

start, of type ScrollTimelineOffset, readonly

A scroll timeline offset which determines the effective scroll offset in the direction specified by orientation that constitutes the beginning of the range in which the timeline is active.

On setting, run the procedure to set the offset value with the provided value as val.

The procedure to set the offset value with val as the provided value 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:

    Return val.

    If val is a CSSNumericValue and matches the grammar <length-percentage>:

    Return val.

    If val is an ElementBasedOffset:

    Return val.

    Otherwise,

    Do not set the value and throw a DOMException with error name SyntaxError.

end, of type ScrollTimelineOffset, readonly

A scroll timeline offset which determines the effective scroll offset in the direction specified by orientation that constitutes the end of the range in which the timeline is active.

On setting, run the procedure to set the offset value with the provided value as val.

timeRange, of type (double or ScrollTimelineAutoKeyword), readonly

A time duration that allows mapping between a distance scrolled, and quantities specified in time units, such as an animation’s duration and start delay.

Conceptually, timeRange represents the number of milliseconds to map to the scroll range defined by start and end. As a result, this value does not have a correspondence to wall-clock time.

This value is used to compute the timeline’s effective time range, and the mapping is then defined by mapping the scroll distance from start to end, to the effective time range.

We are working to remove the need for timeRange to be declared. The most recent work on this involved introduction of the concept of "progress-based animations" to web animations. <https://github.com/w3c/csswg-drafts/issues/4862>

3.1.3. Scroll Timeline Offset

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 source and in the direction specified by 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 effective scroll offset that is resolved from start. The effective end offset is the effective scroll offset that is resolved from end.

3.1.3.1. Container-based Offset
A container-based offset is a scroll timeline offset that is declared only in relation with the scroll container as specified by source.

A container-based offset is provided in the CSSNumericValue or CSSKeywordValue forms.

The procedure to resolve a container-based offset given offset is as follows:

  1. If any of the following are true:

    The effective scroll offset is null and abort remaining steps.

  2. 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:

    Either the beginning or the ending of source's scroll range in orientation depending on whether the offset is start or end.

    If offset is a CSSNumericValue and matches <length-percentage>:

    The distance indicated by the value along source's scroll range in orientation as expressed by absolute length, a percentage, or a calc() expression that resolves to a <length>.

    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%'.

3.1.3.2. Element-based Offset

An element-based offset is a scroll timeline offset that is declared in terms of the intersection of the scroll container as specified by source and one of its descendents as specified by 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, of type Element

The target whose intersection with source's scrolling box determines the concrete scroll offset.

edge, of type Edge, defaulting to "start"

The edge of source's scrolling box in the direction specified by the orientation which the target should intersect with.

threshold, of type double, defaulting to 0.0

A double in the range of [0.0, 1.0] that represent the percentage of the target that is expected to be visible in source's scrollport at the intersection offset.

The range of the threshold member is not currently checked anywhere. <https://github.com/w3c/csswg-drafts/issues/5203>

The procedure to resolve an element-based offset given offset is as follows:

  1. If any of the following are true:

    The effective scroll offset is null and abort remaining steps.

  2. Let target be offset’s target.

  3. If any of the following are true:

    The effective scroll offset is null and abort remaining steps.

  4. If target 's nearest scroll container ancestor is not source abort remaining steps since the effective scroll offset is null.

  5. Let container box be the source's scrollport.

  6. Let target box be the result of finding the rectangular bounding box (axis-aligned in source’s coordinate space) of target’s transformed border box.

  7. If offset’s 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 orientation.

  8. If offset’s 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 orientation.

  9. Let threshold amount be the result of evaluating the following expression where target dimension is target box’s dimension in the axis determined by orientation.

    threshold amount = threshold × target dimension
  10. Adjust scroll offset by threshold amount as follow:

    If offset’s edge is start,

    scroll offset = scroll offset - threshold amount.

    Otherwise (offset’s edge is end),

    scroll offset = scroll offset + threshold amount.

  11. Clamp the value of scroll offset to be within the source's scroll range.

  12. The effective scroll offset is scroll offset

Note: 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,
    start: {target: image, edge: 'end'},
    end: {target: image, edge: 'start'},
  });

  const slideIn = target.animate({
      transform: ['translateX(0)', 'translateX(50vw)'],
      opacity: [0, 1]
    }, {
      timeline:timeline,
      duration: 1000
    }
  );
}

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);
    start: selector(#image) end;
    end: selector(#image) start;
  }

  #target {
    animation-name: slide-in;
    animation-duration: 1s;
    animation-timeline: image-in-scrollport;
  }

}

3.1.4. The effective time range of a ScrollTimeline

The effective time range of a ScrollTimeline is calculated as follows:

If the timeRange has the value "auto",

The effective time range is the maximum value of the target effect end of all animations directly associated with this timeline.

If any animation directly associated with the timeline has a target effect end of infinity, the effective time range is zero.

Otherwise,

The effective time range is the ScrollTimeline's timeRange.

3.1.5. The effective scroll range of a ScrollTimeline

The procedure to calculate effective scroll range of a ScrollTimeline is as follows:

  1. Run the procedure to resolve a scroll timeline offset for both start and end.

  2. Calculate effective scroll range as follow:

    If effective start offset or effective end offset is null.

    The effective scroll range is null.

    Otherwise

    The effective scroll range is the result of evaluating the following expression:

    [=effective end offset=] - [=effective start offset=]

3.1.6. The phase of a ScrollTimeline

The phase of a ScrollTimeline is calculated as follows:

  1. If any of the following are true:

    The phase is inactive and abort remaining steps.

  2. Let current scroll offset be the current scroll offset of source in the direction specified by orientation.

  3. The phase is the result corresponding to the first matching condition from below:

If current scroll offset is less than effective start offset:

The phase is 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 source in orientation:

The phase is 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 phase is active.

3.1.7. The current time of a ScrollTimeline

The current time of a ScrollTimeline is calculated as follows:

  1. If any of the following are true:

    The current time is an unresolved time value and abort remaining steps.

  2. Let current scroll offset be the current scroll offset of source in the direction specified by orientation.

  3. The current time is the result corresponding to the first matching condition from below:

If current scroll offset is less than effective start offset:

The current time is 0.

If current scroll offset is greater than or equal to effective end offset:

The current time is the effective time range.

Otherwise,

The current time is the result of evaluating the following expression:

(|current scroll offset| - [=effective start offset=]) / [=effective scroll range=] &times; [=effective time range=]

Note: To be considered active a scroll timeline requires its effective start offset and its effective end offset to be non-null. This means that for example if one uses an element-based offset whose target is not a descendant of the scroll timeline source, the timeline remains inactive.

3.2. The '@scroll-timeline' at-rule

Scroll Timelines are specified in CSS using the @scroll-timeline at-rule, defined as follows:

@scroll-timeline = @scroll-timeline <timeline-name> { <declaration-list> }

An @scroll-timeline rule has a name given by the <custom-ident> or <string> in its prelude. The two syntaxes are equivalent in functionality; the name is the value of the ident or string. As normal for <custom-ident>s and <string>s, the names are fully case-sensitive; two names are equal only if they are codepoint-by-codepoint equal. The <custom-ident> additionally excludes the none keyword.

Once specified, a scroll timeline may be associated with a CSS Animation [CSS3-ANIMATIONS] by using the animation-timeline property.

The <declaration-list> 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.

This will likely change in the future. <https://github.com/w3c/csswg-drafts/issues/5167>

3.2.1. Scroll Timeline descriptors

Name: source
For: @scroll-timeline
Value: selector( <id-selector> ) | auto | none
Initial: auto

source descriptor determines the scroll timeline’s source.

The value of source is the result corresponding to the first matching condition from the following:

If source is a 'selector()'

The scroll container identified by the <id-selector>.

If source is auto

The scrollingElement of the Document associated with the Window that is the current global object.

Otherwise (source is none)

null.

Consider choosing animation target’s nearest scrollable ancestor instead of document’s scrolling Element for auto. <https://github.com/w3c/csswg-drafts/issues/4338>

Name: orientation
For: @scroll-timeline
Value: auto | block | inline | horizontal | vertical
Initial: auto

orientation descriptor determines the scroll timeline’s orientation.

Name: start
For: @scroll-timeline
Value: <scroll-timeline-offset>
Initial: auto

start descriptor determines the scroll timeline’s start.

Scroll timeline offsets in CSS are represented by the <scroll-timeline-offset> type:

<scroll-timeline-offset> = auto | <length-percentage> | <element-offset>
<element-offset> = selector( <id-selector> ) [<element-offset-edge> || <number>]?
<element-offset-edge> = start | end

The offset type depends on the value of <scroll-timeline-offset> per following:

If value is "auto" or of type <length-percentage>

The scroll timeline offset is a container-based offset with the same value.

If value is of type <element-offset>

The scroll timeline offset is an element-based offset with the following member values:

Name: end
For: @scroll-timeline
Value: <scroll-timeline-offset>
Initial: auto

end descriptor determines the scroll timeline’s end.

Name: time-range
For: @scroll-timeline
Value: auto | <time>
Initial: auto

time-range descriptor determines the scroll timeline’s timeRange.

3.2.2. The CSSScrollTimelineRule Interface

[Exposed=Window]
interface CSSScrollTimelineRule : CSSRule {
    readonly attribute CSSOMString name;
    readonly attribute CSSOMString source;
    readonly attribute CSSOMString orientation;
    readonly attribute CSSOMString start;
    readonly attribute CSSOMString end;
    readonly attribute CSSOMString timeRange;
};
name, of type CSSOMString, readonly
The name associated with the @scroll-timeline rule.
source, of type CSSOMString, readonly
The source descriptor associated with the @scroll-timeline, or "auto" if not specified.
orientation, of type CSSOMString, readonly
The orientation descriptor associated with the @scroll-timeline, or "auto" if not specified.
start, of type CSSOMString, readonly
The start descriptor associated with the @scroll-timeline, or "auto" if not specified.
end, of type CSSOMString, readonly
The end descriptor associated with the @scroll-timeline, or "auto" if not specified.
timeRange, of type CSSOMString, readonly
The time-range descriptor associated with the @scroll-timeline, or "auto" if not specified.

3.3. Examples

Draw a reading progress bar along the top of the page as the user scrolls
#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" }
    ],
    {
      duration: 1000,
      easing: "linear",
      fill: "forwards"
    });
  let timeline = new ScrollTimeline({
    scrollSource: 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-duration: 1s;
    animation-fill-mode: forwards;
    animation-timing-function: linear;
  }

}

4. Avoiding cycles with layout

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

This appendix is informative.

There are no known security or privacy impacts of this feature.

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.

  2. Does this specification deal with high-value data?

    No.

  3. Does this specification introduce new state for an origin that persists across browsing sessions?

    No.

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

    No.

  5. Does this specification expose any other data to an origin that it doesn’t currently have access to?

    No.

  6. Does this specification enable new script execution/loading mechanisms?

    No.

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

    No.

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

    No.

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

    No.

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

    No.

  11. Does this specification allow an origin some measure of control over a user agent’s native UI?

    No.

  12. Does this specification expose temporary identifiers to the web?

    No.

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

    No.

  14. 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.

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

    No.

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

    Yes.

  17. Does this specification allow downgrading default security characteristics?

    No.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Advisements are normative sections styled to evoke special attention and are set apart from other normative text with <strong class="advisement">, like this: UAs MUST provide an accessible alternative.

Conformance classes

Conformance to this specification is defined for three conformance classes:

style sheet
A CSS style sheet.
renderer
A UA that interprets the semantics of a style sheet and renders documents that use them.
authoring tool
A UA that writes a style sheet.

A style sheet is conformant to this specification if all of its statements that use syntax defined in this module are valid according to the generic CSS grammar and the individual grammars of each feature defined in this module.

A renderer is conformant to this specification if, in addition to interpreting the style sheet as defined by the appropriate specifications, it supports all the features defined by this specification by parsing them correctly and rendering the document accordingly. However, the inability of a UA to correctly render a document due to limitations of the device does not make the UA non-conformant. (For example, a UA is not required to render color on a monochrome monitor.)

An authoring tool is conformant to this specification if it writes style sheets that are syntactically correct according to the generic CSS grammar and the individual grammars of each feature in this module, and meet all other conformance requirements of style sheets as described in this module.

Partial implementations

So that authors can exploit the forward-compatible parsing rules to assign fallback values, CSS renderers must treat as invalid (and ignore as appropriate) any at-rules, properties, property values, keywords, and other syntactic constructs for which they have no usable level of support. In particular, user agents must not selectively ignore unsupported component values and honor supported values in a single multi-value property declaration: if any value is considered invalid (as unsupported values must be), CSS requires that the entire declaration be ignored.

Implementations of Unstable and Proprietary Features

To avoid clashes with future stable CSS features, the CSSWG recommends following best practices for the implementation of unstable features and proprietary extensions to CSS.

Non-experimental implementations

Once a specification reaches the Candidate Recommendation stage, non-experimental implementations are possible, and implementors should release an unprefixed implementation of any CR-level feature they can demonstrate to be correctly implemented according to spec.

To establish and maintain the interoperability of CSS across implementations, the CSS Working Group requests that non-experimental CSS renderers submit an implementation report (and, if necessary, the testcases used for that implementation report) to the W3C before releasing an unprefixed implementation of any CSS features. Testcases submitted to W3C are subject to review and correction by the CSS Working Group.

Further information on submitting testcases and implementation reports can be found from on the CSS Working Group’s website at http://www.w3.org/Style/CSS/Test/. Questions should be directed to the public-css-testsuite@w3.org mailing list.

CR exit criteria

For this specification to be advanced to Proposed Recommendation, there must be at least two independent, interoperable implementations of each feature. Each feature may be implemented by a different set of products, there is no requirement that all features be implemented by a single product. For the purposes of this criterion, we define the following terms:

independent
each implementation must be developed by a different party and cannot share, reuse, or derive from code used by another qualifying implementation. Sections of code that have no bearing on the implementation of this specification are exempt from this requirement.
interoperable
passing the respective test case(s) in the official CSS test suite, or, if the implementation is not a Web browser, an equivalent test. Every relevant test in the test suite should have an equivalent test created if such a user agent (UA) is to be used to claim interoperability. In addition if such a UA is to be used to claim interoperability, then there must one or more additional UAs which can also pass those equivalent tests in the same way for the purpose of interoperability. The equivalent tests must be made publicly available for the purposes of peer review.
implementation
a user agent which:
  1. implements the specification.
  2. is available to the general public. The implementation may be a shipping product or other publicly available version (i.e., beta version, preview release, or "nightly build"). Non-shipping product releases must have implemented the feature(s) for a period of at least one month in order to demonstrate stability.
  3. is not experimental (i.e., a version specifically designed to pass the test suite and is not intended for normal usage going forward).

The specification will remain Candidate Recommendation for at least six months.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-ANIMATIONS-2]
CSS Animations Module Level 2 URL: https://drafts.csswg.org/css-animations-2/
[CSS-OVERFLOW-3]
David Baron; Elika Etemad; Florian Rivoal. CSS Overflow Module Level 3. 3 June 2020. WD. URL: https://www.w3.org/TR/css-overflow-3/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS Syntax Module Level 3. 16 July 2019. CR. URL: https://www.w3.org/TR/css-syntax-3/
[CSS-TYPED-OM-1]
Shane Stephens; Tab Atkins Jr.; Naina Raisinghani. CSS Typed OM Level 1. 10 April 2018. WD. URL: https://www.w3.org/TR/css-typed-om-1/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 6 June 2019. CR. URL: https://www.w3.org/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 31 January 2019. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS-WRITING-MODES-4]
Elika Etemad; Koji Ishii. CSS Writing Modes Level 4. 30 July 2019. CR. URL: https://www.w3.org/TR/css-writing-modes-4/
[CSS2]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 7 June 2011. REC. URL: https://www.w3.org/TR/CSS2/
[CSS3-ANIMATIONS]
Dean Jackson; et al. CSS Animations Level 1. 11 October 2018. WD. URL: https://www.w3.org/TR/css-animations-1/
[CSSOM-1]
Simon Pieters; Glenn Adams. CSS Object Model (CSSOM). 17 March 2016. WD. URL: https://www.w3.org/TR/cssom-1/
[CSSOM-VIEW-1]
Simon Pieters. CSSOM View Module. 17 March 2016. WD. URL: https://www.w3.org/TR/cssom-view-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. Selectors Level 4. 21 November 2018. WD. URL: https://www.w3.org/TR/selectors-4/
[WEB-ANIMATIONS-1]
Brian Birtles; et al. Web Animations. 11 October 2018. WD. URL: https://www.w3.org/TR/web-animations-1/
[WebIDL]
Boris Zbarsky. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

Informative References

[CSS-BOX-4]
Elika Etemad. CSS Box Model Module Level 4. 21 April 2020. WD. URL: https://www.w3.org/TR/css-box-4/

Property Index

No properties defined.

@scroll-timeline Descriptors

Name Value Initial
end <scroll-timeline-offset> auto
orientation auto | block | inline | horizontal | vertical auto
source selector( <id-selector> ) | auto | none auto
start <scroll-timeline-offset> auto
time-range auto | <time> auto

IDL Index

enum ScrollDirection {
  "block",
  "inline",
  "horizontal",
  "vertical"
};

enum ScrollTimelineAutoKeyword { "auto" };

typedef (CSSNumericValue or CSSKeywordish) ContainerBasedOffset;
typedef (ContainerBasedOffset or ElementBasedOffset) ScrollTimelineOffset;

dictionary ScrollTimelineOptions {
  Element? source = null;
  ScrollDirection orientation = "block";
  ScrollTimelineOffset start = "auto";
  ScrollTimelineOffset end = "auto";
  (double or ScrollTimelineAutoKeyword) timeRange = "auto";
};

[Exposed=Window]
interface ScrollTimeline : AnimationTimeline {
  constructor(optional ScrollTimelineOptions options = {});
  readonly attribute Element? source;
  readonly attribute ScrollDirection orientation;
  readonly attribute ScrollTimelineOffset start;
  readonly attribute ScrollTimelineOffset end;
  readonly attribute (double or ScrollTimelineAutoKeyword) timeRange;
};

enum Edge { "start", "end" };

dictionary ElementBasedOffset {
  Element target;
  Edge edge = "start";
  double threshold = 0.0;
};

[Exposed=Window]
interface CSSScrollTimelineRule : CSSRule {
    readonly attribute CSSOMString name;
    readonly attribute CSSOMString source;
    readonly attribute CSSOMString orientation;
    readonly attribute CSSOMString start;
    readonly attribute CSSOMString end;
    readonly attribute CSSOMString timeRange;
};

Issues Index

These use cases need updating. <https://github.com/w3c/csswg-drafts/issues/4354>
We are working to remove the need for timeRange to be declared. The most recent work on this involved introduction of the concept of "progress-based animations" to web animations. <https://github.com/w3c/csswg-drafts/issues/4862>
The range of the threshold member is not currently checked anywhere. <https://github.com/w3c/csswg-drafts/issues/5203>
This will likely change in the future. <https://github.com/w3c/csswg-drafts/issues/5167>
Consider choosing animation target’s nearest scrollable ancestor instead of document’s scrolling Element for auto. <https://github.com/w3c/csswg-drafts/issues/4338>