CSS 动画 Worklet API

W3C 第一次公开工作草案,

此版本:
https://www.w3.org/TR/2019/WD-css-animation-worklet-1-20190625/
最新发布版本:
https://www.w3.org/TR/css-animation-worklet-1/
编辑草案:
https://drafts.css-houdini.org/css-animationworklet-1/
反馈:
public-houdini@w3.org 主题为 “[css-animation-worklet] … 消息主题 …” (存档)
问题跟踪:
规范中的问题
GitHub 问题
编辑:

摘要

动画 Worklet API 提供了一种创建脚本动画的方法,该动画控制一组 动画效果。该 API 的设计使得用户代理可以在自己的专用线程中运行此类动画,从而与主线程提供一定程度的性能隔离。

本文件状态

本节描述了本文档在发布时的状态。其他文档可能会取代本文件。W3C 当前出版物列表和本技术报告的最新版本可在 W3C 技术报告索引 https://www.w3.org/TR/ 找到。

本文档是 第一次公开工作草案

作为第一次公开工作草案发布并不意味着 W3C 会员的认可。这是一份草案文档,可能随时更新、替换或被其他文档取代。引用本文档为工作进展以外的用途是不合适的。

GitHub 问题 是讨论此规范的首选方式。 提交问题时,请在标题中包含“css-animation-worklet”字样,最好像这样: “[css-animation-worklet] …评论摘要…”。 所有问题和评论都将存档

本文档由 CSS 工作组 制作。

本文档由遵循 W3C 专利政策 的小组制作。W3C 维护了一份任何与小组交付物相关的专利公开声明的公共列表; 该页面还包括专利公开的说明。了解含有 必要声明 的专利的个人,必须根据 W3C 专利政策第6节 公开相关信息。

本文档受 2019年3月1日 W3C 流程文档 管理。

1. 简介

本节非规范性。

本文档介绍了一种新的原语,它提供了 Web 动画的可扩展性,并在 Web 上实现了高性能的交互式过程动画。有关详细的理由和动机,请参见 [解释器][原则]

动画 Worklet API 提供了一种创建脚本动画的方法,这些动画控制一组 动画效果。该 API 设计使得用户代理可以在其专用线程中运行此类动画,从而与主线程提供一定程度的性能隔离。

1.1. 与 Web 动画 API 的关系

本节非规范性。

动画 Worklet 执行上下文中运行的动画在主 JavaScript 执行上下文中暴露了来自 Web 动画规范的 动画 接口。这意味着它们可以使用相同的 Web 动画 API 从主线程进行控制和检查。

2. 动画 Worklet

动画 Worklet 是一个 Worklet ,负责与自定义动画相关的所有类。Worklet 可以通过 animationWorklet 属性访问。

animationWorkletworklet 全局范围类型AnimationWorkletGlobalScope

AnimationWorkletGlobalScope 表示 animationWorklet 的全局执行上下文。

[Exposed=Window]
partial namespace CSS {
    [SameObject] readonly attribute Worklet animationWorklet;
};

3. 动画师

动画师 代表了在动画线程上运行的动画实例。 动画师通过唯一的名称进行识别,并根据当前的输入时间确定动画如何推进其关键帧效果。动画师 实例存在于 AnimationWorkletGlobalScope 中,每个实例都与一个 WorkletAnimation 实例相关联。动画师只能通过构造 WorkletAnimation 来实例化。

支持两种动画师类型:无状态动画师有状态动画师 ,每个提供不同的状态管理策略。

3.1. 无状态动画师接口

此接口表示一个无状态动画师。此类动画师不依赖于存储在实例或全局范围内的任何本地状态。实际上,无状态动画师 的动画函数可以被视为纯函数,期望在相同的输入下产生相同的输出。

[Exposed=AnimationWorklet, Global=AnimationWorklet, Constructor (optional any options)]
interface StatelessAnimator {
};
这是类应有的样子。
class FooAnimator extends StatelessAnimator {
    constructor(options) {
        // 当一个新的动画师被实例化时调用。
    }
    animate(currentTime, effect) {
        // 动画帧逻辑在此。
    }
}

注意: 无状态使动画工作流能够执行优化,例如并行生成多个动画帧,并进行非常低成本的拆卸和设置。强烈推荐使用无状态动画师,以启用此类优化。

3.2. 有状态动画师接口

此接口表示一个有状态的动画师。该动画师可以有本地状态,并且动画工作流保证只要有状态动画师履行如下所述的接口要求,它的状态将被维护。

动画 Worklet 维护着一组可能存在于不同线程或进程中的 WorkletGlobalScope。 动画 worklet 可能会暂时终止某个全局范围(例如,为了节省资源),或在不同全局范围之间移动一个正在运行的 动画师实例(例如,如果其效果只能在某一特定线程中发生变化)。动画 worklet 保证有状态动画师实例的状态即使在不同的全局范围中重新生成时也能保持。

维护状态的基本机制是动画 worklet 快照通过 state 函数暴露的本地状态,并将其实例化,以便在稍后可能在不同全局范围内重新生成动画师实例时,将其传递给构造函数。迁移动画师实例 算法详细说明了这一过程。

用户定义的有状态动画师需履行以下要求:其 state 函数返回一个对象,表示其状态,该状态可使用结构化序列化算法进行序列化;同时,构造函数也能根据传递给它的同一对象重新创建其状态。

[Exposed=AnimationWorklet, Global=AnimationWorklet,
Constructor (optional any options, optional any state)]
interface StatefulAnimator {
  any state();
};
这是类应有的样子。
class BarAnimator extends StatefulAnimator {
    constructor(options, state) {
      // 当一个新的动画师被实例化时(无论是首次还是重新生成后)。
      this.currentVelocity  = state ? state.velocity : 0;
    }
    animate(currentTime, effect) {
        // 动画帧逻辑在此,可以依赖 this.currentVelocity。
        this.currentVelocity += 0.1;
    }
    state() {
      // 返回的对象应使用结构化克隆算法进行序列化。
      return {
        velocity: this.currentVelocity;
      }
    }
}

3.3. 动画师定义

动画师定义 是一个结构,它根据 AnimationWorkletGlobalScope 的需要描述作者定义的自定义动画。 它包括:

3.4. 注册动画师定义

AnimationWorkletGlobalScope 具有一个动画师名称到动画师定义的映射。 当调用 registerAnimator(name, animatorCtor) 时,映射会被填充。
[ Exposed=AnimationWorklet, Global=AnimationWorklet ]
interface AnimationWorkletGlobalScope : WorkletGlobalScope {
    void registerAnimator(DOMString name, AnimatorInstanceConstructor animatorCtor);
};

callback AnimatorInstanceConstructor = any (any options, optional any state);

当在AnimationWorkletGlobalScope 中调用 registerAnimator(name, animatorCtor) 方法时,用户代理必须运行以下步骤:

  1. 如果 name 不是有效的 <标识符>抛出 TypeError 并中止这些步骤。

  2. 如果 name 作为键存在于动画师名称到动画师定义的映射中,抛出 NotSupportedError 并中止所有这些步骤。

  3. 如果 IsConstructor(animatorCtor) 的结果为 false抛出 TypeError 并中止所有这些步骤。

  4. prototype 为调用 Get(animatorCtor, "prototype") 的结果。

  5. 如果 SameValue(prototype, 无状态动画师) 为 true,则将 stateful 设置为 false,否则如果 SameValue(prototype, 有状态动画师) 为 true,则将 stateful 设置为 true,否则抛出 TypeError 并中止所有这些步骤。

  6. animateValue 为调用 Get(prototype, "animate") 的结果。

  7. animate转换 animateValue函数 回调函数 类型的结果。如果抛出异常,请重新抛出异常并中止这些步骤。

  8. definition 为新的 动画师定义,其中包括:

  9. 将键值对 (name - definition) 添加到 动画师名称到动画师定义的映射 中。

4. 动画师实例

动画师实例 是一个结构, 描述了在AnimationWorkletGlobalScope中完全实现的自定义动画实例。 它引用了一个动画师定义,并拥有特定实例状态,如动画效果和时间线。它包括:

一个有状态动画师实例 是一个 动画师实例,其对应的 动画师定义有状态标志true

4.1. 创建动画师实例

每个动画师实例 存在于AnimationWorkletGlobalScope中。

每个AnimationWorkletGlobalScope 具有一个动画师实例集。当用户代理在AnimationWorkletGlobalScope 作用域中构造一个新的动画师实例时,该集合将被填充。每个动画师实例对应于文档作用域中的一个 worklet 动画。

为给定的nametimelineeffectserializedOptionsserializedStateworkletGlobalScope,用户代理必须运行以下步骤以创建一个新的动画师实例

  1. definition为在workletGlobalScope动画师名称到动画师定义映射中查找name的结果。

    如果definition不存在,终止以下步骤。

  2. animatorCtordefinition类构造函数

  3. options结构化反序列化(serializedOptions)的结果。

  4. state结构化反序列化(serializedState)的结果。

  5. animatorInstance为使用«optionsstate»作为参数构造animatorCtor的结果。如果抛出异常,重新抛出异常并终止所有这些步骤。

  6. animatorInstance上设置以下内容:

  7. animatorInstance添加到workletGlobalScope动画师实例集

4.2. 运行动画师

当用户代理希望生成一个新的动画帧时,如果任何动画师实例的 关联动画请求标志帧请求,则用户代理必须为当前帧运行动画师

注意:用户代理不需要在每个视觉帧上运行动画。可以推迟到后续帧生成动画帧。这允许用户代理根据其策略提供不同的服务级别。

当用户代理想要在给定的workletGlobalScope运行动画器时,它必须遍历workletGlobalScope中的所有动画器实例,并迭代workletGlobalScope动画器实例集。对于每个这样的实例,用户代理必须执行以下步骤:

  1. animatorNameinstance动画师名称

  2. definition为在workletGlobalScope动画师名称到动画师定义映射中查找animatorName的结果。

    如果definition不存在,则中止以下步骤。

  3. 如果instance动画请求标志当前帧, 或者instance所属的效果不会在当前帧的可视视口内可见,用户代理可以中止所有后续步骤。

    可以考虑允许用户代理跳过运行动画师实例,以限制缓慢的动画师。

  4. animateFunctiondefinition动画函数

  5. currentTimeinstance动画师当前时间

  6. effectinstance动画师效果

  7. 调用animateFunction,参数为«currentTimeeffect», 并以instance作为回调的 this 值

注意:虽然效率较低,但用户代理在同一帧中多次运行动画师是合法的。

需要明确说明如果 animateFunction 抛出异常会发生什么。至少需要说明关键帧的 localTime 值会被忽略,以避免不正确的部分更新。

4.3. 移除动画师实例

为给定的instanceworkletGlobalScope移除一个动画师实例,用户代理必须执行以下步骤:

  1. instanceworkletGlobalScope动画师实例集中移除。

4.4. 迁移动画师实例

迁移过程允许有状态动画师实例迁移到不同的 WorkletGlobalScope 而不丢失其本地状态。

要将一个动画师实例迁移从一个WorkletGlobalScope 迁移到另一个,给定instancesourceWorkletGlobalScopedestinationWorkletGlobalScope,用户代理必须执行以下步骤:

  1. serializedState未定义。

  2. sourceWorkletGlobalScope上排队一个任务,执行以下步骤:

    1. animatorNameinstance动画师名称

    2. definition为在sourceWorkletGlobalScope动画师名称到动画师定义映射中查找animatorName的结果。

      如果definition不存在,则中止以下步骤。

    3. statefuldefinition有状态标志

    4. 如果statefulfalse,则中止以下步骤。

    5. stateFunctioninstance的状态函数。

    6. state为调用stateFunction的结果,调用时,instance作为回调的 this 值。如果抛出任何异常,请重新抛出异常并中止 以下步骤。

    7. serializedState设置为结构化序列化(state)的结果。 如果抛出任何异常,则中止以下步骤。

    8. 执行移除动画师实例的过程,给定 instancesourceWorkletGlobalScope

  3. 等待上述任务完成。如果任务中止,停止以下步骤。

  4. destinationWorkletGlobalScope上排队一个任务,执行以下步骤:

    1. 执行创建新的动画师实例的过程, 给定以下参数:

如果动画师状态 getter 抛出异常,用户代理将移除动画师,但不会重新创建它。 这实际上移除了动画师实例。

4.5. 请求动画帧

每个动画师实例 关联一个动画请求标志。它必须是 帧请求当前帧。它最初设置为当前帧。不同的情况可能会导致动画请求标志被 设置为帧请求。 包括以下情况:

§4.2 运行动画师将动画师上的动画请求标志重置为 当前帧

5. Web 动画集成

5.1. Worklet 动画

Worklet 动画是一种 动画,它将动画播放委托给 一个动画师实例。它控制其对应的动画师实例的生命周期和播放状态。

作为一个动画worklet 动画具有动画效果时间线。但是,不同于其他动画,worklet 动画的 当前时间不会直接决定动画效果的 本地时间 (通过其继承时间)。相反,关联的 动画师实例直接控制动画效果的 本地时间。请注意,这意味着时间线的当前时间不能完全决定 动画的输出。

Worklet 动画 除了Animation 接口外,还具有以下属性:

WorkletAnimation 时间模型概述
WorkletAnimation 时间模型概述。

动画的当前时间输入到动画师实例中,生成动画效果的本地时间值。如果动画师实例在并行全局作用域中运行,实现还可以选择使用本地时间值生成最终效果值,并并行更新视觉效果。

5.2. 创建 Worklet 动画

[Exposed=Window,
 Constructor (DOMString animatorName,
              optional (AnimationEffect or sequence<AnimationEffect>)? effects = null,
              optional AnimationTimeline? timeline,
              optional any options)]
interface WorkletAnimation : Animation {
        readonly attribute DOMString animatorName;
};

WorkletAnimation(animatorName, effects, timeline, options)

使用以下过程创建一个新的WorkletAnimation 对象。

  1. workletAnimation为一个新的WorkletAnimation 对象。

  2. 运行设置动画时间线的过程,传递timeline作为新的时间线,或者,如果未提供timeline参数, 则传递与Window关联的 默认文档时间线

  3. 根据以下条件匹配第一个结果,令effect为对应的结果。

    如果effects是一个AnimationEffect对象,

    effecteffects

    如果effects是一个AnimationEffect对象的列表,

    effect为一个新的WorkletGroupEffect,其子级设置为effects

    否则,

    effect为未定义。

  4. 运行设置动画目标效果的过程,传递effect作为新的效果。

  5. serializedOptions结构化序列化(options)的结果。 重新抛出任何异常。

  6. workletAnimation序列化选项设置为serializedOptions

  7. workletAnimation动画师名称设置为animatorName

5.3. Worklet 动画时间模型

本节描述了worklet 动画的时间模型与其他 动画的不同之处。

除了现有条件下何时将动画视为 就绪worklet 动画 只有在以下条件也为真时,才会被视为就绪

§5.1 Worklet 动画中所述, worklet 动画当前时间不会决定其 动画效果本地时间。相反,关联的 动画师实例 直接控制动画效果的本地时间。这意味着动画效果的本地时间由可能在并行执行上下文中的 WorkletGlobalScope控制。

以下是上述语义的几个含义:

如果 Worklet 动画在并行 worklet 执行上下文中执行,则应定期将其动画效果的最新状态同步回主 JavaScript 执行上下文。从并行 worklet 执行上下文到主 JavaScript 执行上下文的 效果值同步必须在文档生命周期中 运行动画帧回调之前进行。 请注意,由于此动画模型的异步性质,当主 JavaScript 执行上下文中的脚本读取由 Worklet 动画 动画的目标属性时,可能会看到陈旧的值, 而与当前用于生成用户可见的视觉帧的值不同。这类似于异步滚动时读取主 JavaScript 执行上下文中的滚动偏移量的效果。

为动画师实例在其 动画 currentTime 发生变化时(例如,通过 reverse()、finish() 或 playbackRate 更改)提供适当的机制进行通知。 这样它可以做出适当的反应。 <https://github.com/w3c/css-houdini-drafts/issues/811>

5.4. 与动画师实例的交互

一个worklet 动画在任何时间最多对应一个动画师实例,并且可能没有当前对应的动画师实例。对于worklet 动画,其播放状态决定了对应的动画师实例

为了给定workletAnimation关联动画师实例, 用户代理必须执行以下步骤:

  1. 如果workletAnimation已经有一个对应的动画师实例,则中止后续步骤。

  2. workletGlobalScope为与workletAnimation关联的AnimationWorkletGlobalScope

  3. 排队一个任务workletGlobalScope上,运行创建新动画师实例的过程,传递:

    • 作为名称的workletAnimation动画师名称

    • 作为时间线的workletAnimation时间线

    • 作为效果的workletAnimation动画效果

    • 作为选项的workletAnimation序列化选项

    • 作为workletGlobalScopeworkletGlobalScope

  4. 如果该过程成功,则将生成的动画师实例设置为与workletAnimation对应。

为了给定workletAnimation取消关联动画师实例, 用户代理必须执行以下步骤:

  1. 如果workletAnimation没有对应的动画师实例,则中止后续步骤。

  2. workletGlobalScope为与workletAnimation关联的AnimationWorkletGlobalScope

  3. animatorInstanceworkletAnimation对应的动画师实例

  4. 排队一个任务workletGlobalScope上,运行移除动画师实例的过程,传递animatorInstance作为实例,并传递workletGlobalScope

  5. workletAnimation设置为没有对应的动画师实例

为了给定workletAnimation设置动画师实例, 用户代理必须执行以下步骤:

  1. 取消关联动画师实例给定workletAnimation

  2. 关联动画师实例给定workletAnimation

当给定的workletAnimation播放状态变为 待处理运行暂停时, 执行关联动画师实例给定workletAnimation的过程。

当给定的workletAnimation播放状态变为 空闲已完成时, 执行取消关联动画师实例给定workletAnimation的过程。

当为给定的workletAnimation调用设置动画的目标效果的过程时,执行设置动画师实例给定workletAnimation的过程。

当为给定的workletAnimation调用设置动画的时间线的过程时,执行设置动画师实例给定workletAnimation的过程。

5.5. 滚动时间线

本节非规范性。

ScrollTimeline 是一个提议添加到Web动画API的新概念。它定义了一个动画时间线,其时间值取决于滚动容器的滚动位置。Worklet动画 可以有一个滚动时间线,从而根据滚动偏移驱动它们的脚本效果。

注意: 访问输入:我们有兴趣暴露除滚动以外的其他用户输入(例如,触摸/指针输入)给这些动画,以便作者可以创建无卡顿的输入驱动动画,而这些动画在当今并不太可能实现。我们仍在努力找出实现这一目标的正确抽象和机制。

5.6. WorkletGroupEffect

WorkletGroupEffect 是一种组效果,它允许其子效果本地时间单独变更。

当一个WorkletGroupEffect 被设置为动画效果,并与Worklet动画关联时, 对应的动画师实例可以直接控制子效果本地时间。这允许单个worklet动画协调多个效果——参见§8.2 示例2:视差背景。中的一个使用场景示例。

[Exposed=AnimationWorklet]
interface WorkletGroupEffect {
  sequence<AnimationEffect> getChildren();
};

[Exposed=AnimationWorklet]
partial interface AnimationEffect {
    // 用于Animation Worklet范围内驱动效果。
    attribute double localTime;
};

为了将t值设置为effectlocalTime属性, 用户代理应执行以下第一个匹配条件对应的操作:

如果effect没有父组,

effect的本地时间设置为t

如果effect有父组,且父组类型为WorkletGroupEffect

将效果开始时间设置为(父级的变换时间- t)。注意这实际上设置了effect的本地时间为t。

否则

抛出一个异常,指出子效果时间只能由其父组控制。

上述接口暴露了作为web-animation-2一部分提议的组效果的保守子集。我们应该将其移到对web动画的增量规范中。<https://github.com/w3c/csswg-drafts/issues/2071>

5.7. 效果堆栈和组合顺序

与其他动画一样,worklet动画参与了效果堆栈。worklet动画没有特定的动画类,这意味着它与其他由JavaScript创建的Web动画具有相同的组合顺序。

6. 安全性考虑

这些特性没有已知的安全问题。

7. 隐私考虑

这些特性没有已知的隐私问题。

8. 示例

8.1. 示例1:Twitter 头部。

一个展示Twitter个人资料头部效果的示例,其中两个元素(头像和头部)根据滚动偏移同步更新。
// 在文档范围内。
<div id='scrollingContainer'>
  <div id='header' style='height: 150px'></div>
  <div id='avatar'><img></div>
</div>

<script>
await CSS.animationWorklet.addModule('twitter-header-animator.js');
const animation = new WorkletAnimation(
    'twitter-header',
    [new KeyframeEffect($avatar,  /* 向上滚动时缩放 */
                    [{transform: 'scale(1)'}, {transform: 'scale(0.5)'}],
                    {duration: 1000, iterations: 1}),
    new KeyframeEffect($header, /* 向上滚动时透明度降低 */
                    [{opacity: 0}, {opacity: 0.8}],
                    {duration: 1000, iterations: 1})],
    new ScrollTimeline({
      scrollSource: $scrollingContainer,
      orientation: 'block',
      timeRange: 1000,
      startScrollOffset: 0,
      endScrollOffset: $header.clientHeight}));
animation.play();

// 由于此动画使用的是组效果,同一动画实例可以通过不同的句柄访问:$avatarEl.getAnimations()[0], $headerEl.getAnimations()[0]

</script>
// 在AnimationWorkletGlobalScope内。
registerAnimator('twitter-header', class HeaderAnimator extends StatelessAnimator {
  constructor(options) {
    this.timing_ = new CubicBezier('ease-out');
  }

  animate(currentTime, effect) {
    const scroll = currentTime;  // 滚动值在[0, 1000]范围内

    // 通过单独设置其子效果的本地时间来驱动输出组效果。
    effect.children[0].localTime = scroll;
    effect.children[1].localTime = this.timing_(clamp(scroll, 0, 500));
  }
});

function clamp(value, min, max) {
  return Math.min(Math.max(value, min), max);
}

8.2. 示例2:视差背景。

一个简单的视差背景示例。
<style>
.parallax {
    position: fixed;
    top: 0;
    left: 0;
    opacity: 0.5;
}
</style>
<div id='scrollingContainer'>
  <div id="slow" class="parallax"></div>
  <div id="fast" class="parallax"></div>
</div>

<script>
await CSS.animationWorklet.addModule('parallax-animator.js');
const scrollTimeline = new ScrollTimeline({
  scrollSource: $scrollingContainer,
  orientation: 'block',
  timeRange: 1000
});
const scrollRange = $scrollingContainer.scrollHeight - $scrollingContainer.clientHeight;

const slowParallax = new WorkletAnimation(
    'parallax',
    new KeyframeEffect($parallax_slow, [{'transform': 'translateY(0)'}, {'transform': 'translateY(' + -scrollRange + 'px)'}], {duration: 1000}),
    scrollTimeline,
    {rate : 0.4}
);
slowParallax.play();

const fastParallax = new WorkletAnimation(
    'parallax',
    new KeyframeEffect($parallax_fast, [{'transform': 'translateY(0)'}, {'transform': 'translateY(' + -scrollRange + 'px)'}], {duration: 1000}),
    scrollTimeline,
    {rate : 0.8}
);
fastParallax.play();
</script>
// 在 AnimationWorkletGlobalScope 内。
registerAnimator('parallax', class ParallaxAnimator extends StatelessAnimator {
  constructor(options) {
    this.rate_ = options.rate;
  }

  animate(currentTime, effect) {
    effect.localTime = currentTime * this.rate_;
  }
});

一致性

文档约定

一致性要求通过描述性断言和RFC 2119术语的组合来表达。关键字“必须(MUST)”,“不得(MUST NOT)”,“要求(REQUIRED)”,“应(SHALL)”,“不应(SHALL NOT)”,“应该(SHOULD)”,“不应该(SHOULD NOT)”,“建议(RECOMMENDED)”,“可以(MAY)”和“可选(OPTIONAL)”在本文件的规范部分中应按照RFC 2119中的解释进行理解。不过,为了可读性,这些词在本规范中并未全部使用大写字母。

本规范的所有文本均为规范性内容,除非明确标记为非规范性的部分、示例和注释。[RFC2119]

本规范中的示例通过“例如”引出,或与规范文本分开,使用class="example"标记,例如:

这是一个信息性示例。

信息性注释以“注释”开头,并与规范文本分开,使用class="note"标记,例如:

注释,这是一个信息性注释。

建议性条文为规范部分,样式为醒目,使用<strong class="advisement">标记,例如:用户代理(UAs)必须提供可访问的替代方案。

一致性类别

本规范的一致性分为三类:

样式表
CSS样式表
渲染器
解释样式表语义并渲染使用样式表的文档的用户代理(UA)
创作工具
编写样式表的用户代理(UA)

样式表符合本规范的要求,前提是其使用本模块定义的语法的所有声明都符合通用CSS语法和本模块中每个功能定义的个体语法。

渲染器符合本规范的要求,不仅需要按照适当的规范解释样式表,还要正确解析并支持本规范定义的所有功能,进而正确渲染文档。然而,如果由于设备限制而无法正确渲染文档,这并不意味着用户代理不符合要求。(例如,用户代理不需要在单色显示器上渲染颜色。)

创作工具符合本规范的要求,前提是它编写的样式表在语法上符合通用CSS语法和本模块中每个功能的个体语法,并且满足本模块中描述的样式表的所有其他一致性要求。

部分实现

为了让作者能够利用向前兼容的解析规则分配回退值,CSS 渲染器必须将其无法支持的任何@规则、属性、属性值、关键字和其他语法结构视为无效(并且适当忽略)。特别是,用户代理不得在单个多值属性声明中选择性忽略不支持的组件值并接受支持的值:如果任何值被认为是无效的(因为不支持的值必须如此),CSS 要求忽略整个声明。

不稳定和专有功能的实现

为了避免与未来稳定的 CSS 功能发生冲突,CSSWG 建议遵循最佳实践来实现不稳定的功能和专有扩展

非实验性实现

一旦规范进入候选推荐阶段(Candidate Recommendation),就可以进行非实验性实现,实施者应发布任何CR级别功能的无前缀实现,前提是他们能够证明其按照规范正确实现。

为了建立和维护 CSS 在不同实现之间的互操作性,CSS 工作组请求非实验性的 CSS 渲染器在发布任何 CSS 功能的无前缀实现之前,向 W3C 提交一份实现报告(如果必要,还包括用于该实现报告的测试用例)。提交给 W3C 的测试用例将由 CSS 工作组进行审查和修正。

关于提交测试用例和实现报告的更多信息,可以从 CSS 工作组的网站https://www.w3.org/Style/CSS/Test/获取。相关问题应通过public-css-testsuite@w3.org邮件列表进行询问。

索引

本规范定义的术语

其他文档定义的术语

参考文献

规范性引用

[CSS-TRANSITIONS-1]
David Baron等人. CSS 过渡效果. 2018年10月11日. WD. URL: https://www.w3.org/TR/css-transitions-1/
[CSS-VALUES-4]
Tab Atkins Jr. 和 Elika Etemad. CSS 值与单位模块 4. 2019年1月31日. WD. URL: https://www.w3.org/TR/css-values-4/
[CSSOM-1]
Simon Pieters 和 Glenn Adams. CSS 对象模型 (CSSOM). 2016年3月17日. WD. URL: https://www.w3.org/TR/cssom-1/
[DOM]
Anne van Kesteren. DOM 标准. 现行标准. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren等人. HTML 标准. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren 和 Domenic Denicola. 基础标准 (Infra). 现行标准. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. 用于指示要求级别的关键字. 1997年3月. 最佳当前实践. URL: https://tools.ietf.org/html/rfc2119
[WEB-ANIMATIONS-1]
Brian Birtles等人. Web 动画. 2018年10月11日. WD. URL: https://www.w3.org/TR/web-animations-1/
[WebIDL]
Boris Zbarsky. Web IDL. 2016年12月15日. ED. URL: https://heycam.github.io/webidl/
[WORKLETS-1]
Ian Kilpatrick. 工作单元 第1级. 2016年6月7日. WD. URL: https://www.w3.org/TR/worklets-1/

信息性引用

[EXPLAINER]
动画工作单元解释器. URL: https://github.com/w3c/css-houdini-drafts/blob/master/css-animationworklet/README.md
[PRINCIPLES]
动画工作单元设计原则与目标. URL: https://github.com/w3c/css-houdini-drafts/blob/master/css-animationworklet/principles.md

IDL 索引

[Exposed=Window]
partial namespace CSS {
    [SameObject] readonly attribute Worklet animationWorklet;
};

[Exposed=AnimationWorklet, Global=AnimationWorklet, Constructor (optional any options)]
interface StatelessAnimator {
};

[Exposed=AnimationWorklet, Global=AnimationWorklet,
Constructor (optional any options, optional any state)]
interface StatefulAnimator {
  any state();
};

[ Exposed=AnimationWorklet, Global=AnimationWorklet ]
interface AnimationWorkletGlobalScope : WorkletGlobalScope {
    void registerAnimator(DOMString name, AnimatorInstanceConstructor animatorCtor);
};

callback AnimatorInstanceConstructor = any (any options, optional any state);


[Exposed=Window,
 Constructor (DOMString animatorName,
              optional (AnimationEffect or sequence<AnimationEffect>)? effects = null,
              optional AnimationTimeline? timeline,
              optional any options)]
interface WorkletAnimation : Animation {
        readonly attribute DOMString animatorName;
};


[Exposed=AnimationWorklet]
interface WorkletGroupEffect {
  sequence<AnimationEffect> getChildren();
};

[Exposed=AnimationWorklet]
partial interface AnimationEffect {
    // Intended for use inside Animation Worklet scope to drive the effect.
    attribute double localTime;
};

问题索引

考虑赋予用户代理跳过执行动画实例的权限,以限制慢速动画的节奏。
应明确规定当 animateFunction 抛出异常时的处理方式。至少,我们应说明忽略关键帧的 localTime 值以避免不正确的部分更新。
animator instance 提供适当的机制,以便在动画的 currentTime 改变时(如通过 reverse()、finish() 或 playbackRate 改变)能够收到通知,并做出相应反应。<https://github.com/w3c/css-houdini-drafts/issues/811>
上述接口暴露的是 web-animation-2 中提议的 GroupEffect 的保守子集。我们应该将其移动到针对 web-animation 的增量规范中。<https://github.com/w3c/csswg-drafts/issues/2071>