CSS 自定义高亮 API 模块第 1 级

W3C 工作草案,

更多关于此文档的详情
当前版本:
https://www.w3.org/TR/2021/WD-css-highlight-api-1-20211215/
最新发布版本:
https://www.w3.org/TR/css-highlight-api-1/
编辑草案:
https://drafts.csswg.org/css-highlight-api-1/
以前的版本:
历史:
https://www.w3.org/standards/history/css-highlight-api-1
反馈:
CSSWG 问题库
内嵌在规格中的问题
编辑者:
Florian Rivoal (代表 Bloomberg)
Sanket Joshi (微软公司)
Megan Gardner (苹果公司)
为此规范建议编辑:
GitHub 编辑器

摘要

此 CSS 模块描述了一种机制,用于对通过脚本标识的文档中的任意范围进行样式设置。

CSS 是一种用于描述结构化文档(如 HTML 和 XML)的渲染语言,适用于屏幕、纸张等介质。

本文档的状态

此部分描述了本文档在发布时的状态。 当前 W3C 出版物列表和该技术报告的最新修订版可以在 W3C 技术报告索引中找到。

本文档由 CSS 工作组工作草案 的形式发布, 使用 推荐轨道。 作为工作草案发布并不意味着 W3C 及其成员的认可。

这是一个草稿文档,可能随时更新、替换或被其他文档取代。作为工作进展,不应将此文档作为参考文献。

请通过 在 GitHub 上提交问题(首选)来发送反馈, 标题中包括规范代码 “css-highlight-api”,例如: “[css-highlight-api] …评论摘要…”。 所有问题和评论都已 归档。 或者,反馈可以发送到 (已归档) 公共邮件列表 www-style@w3.org

本文档受 2021 年 11 月 2 日的 W3C 过程文档 约束。

本文档由根据 W3C 专利政策 运作的小组编写。 W3C 维护了一个 与该小组交付物相关的公开专利披露列表; 该页面还包括披露专利的说明。 个人如果实际知晓专利且认为该专利包含 必要声明,必须根据 W3C 专利政策第 6 节 进行披露。

1. 简介

本节为非规范性内容

自定义高亮 API 扩展了 高亮伪元素 的概念(参见 CSS 伪元素 4 § 3 高亮伪元素), 通过为 web 开发者提供一种方式来设置任意 Range 对象的文本样式, 而不仅限于用户代理定义的 ::selection::inactive-selection::spelling-error, 和 ::grammar-error。 这在多种场景中非常有用, 包括希望实现自定义选择的编辑框架、 在虚拟化文档中实现页面查找、 表示在线协作的多重选择, 或拼写检查框架。

自定义高亮 API 提供了一种编程方式,用于添加和移除不影响底层 DOM 结构的高亮, 而是基于 range 对象来应用样式, 通过 ::highlight() 伪元素进行访问。

以下代码使用 ::highlight() 伪元素 为文本 One two 应用了黄色背景和蓝色前景色。 它通过将一个 Highlight 添加到 HighlightRegistry 中来实现(这两个都是此规范引入的新概念)。 该 Highlight 将包含一个 Range ,其边界点围绕着文本 One two
<style>
  :root::highlight(example-highlight) {
    background-color: yellow;
    color: blue;
  }
</style>
<body><span>One </span><span>two </span><span>three…</span>
<script>
  let r = new Range();
  r.setStart(document.body, 0);
  r.setEnd(document.body, 2);

  CSS.highlights.set("example-highlight", new Highlight(r));
</script>

结果如下所示:

One Two three…

2. 模块交互

本模块依赖于 Infra 标准 [INFRA] 和 WebIDL [WebIDL]

假设您熟悉 CSS 和 DOM 标准 [DOM], 并特别扩展了 CSS 伪元素模块第 4 级 [css-pseudo-4] 中定义的机制来处理 高亮伪元素。 选择器第 4 级 [selectors-4] 规范定义了伪元素的一般工作原理。

参见 参考文献 以获取依赖项的完整列表。

注意: 此草案为早期版本。 随着其逐渐成熟,CSS-WG 可能会决定保留它作为独立模块, 或者可能会将其合并到 [css-pseudo-4] 或该模块的后续版本中。

3. 设置自定义高亮

3.1. 创建自定义高亮

自定义高亮是表示文档部分的范围集合。 它们不一定适合放入元素树中, 可以随意跨越元素边界,而不遵循其嵌套结构。 它们可用于影响文档这些部分的外观 (参见 § 4 自定义高亮的样式设置), 或处理与它们相关的事件 (参见 § 6 事件处理)。

自定义高亮Highlight 对象表示,类似集合对象,其 集合条目AbstractRange 对象。范围可以通过将它们传递给构造函数添加到 自定义高亮中, 或使用类似集合对象的常规 API 来操作其 集合条目

注意:由于 自定义高亮中的范围 是 AbstractRange 对象, 作者可以在使用 Range 对象和 StaticRange 对象之间进行选择。 有关此选择及其影响的更多详细信息,请参见 § 5.2 范围更新与无效化

enum HighlightType {
  "highlight",
  "spelling-error",
  "grammar-error"
};

[Exposed=Window]
interface Highlight {
  constructor(AbstractRange... initialRanges);
  setlike<AbstractRange>;
  attribute long priority;
  attribute HighlightType type;
};

有关 priority 属性的更多信息,请参见 § 4.2.5 重叠高亮的优先级

有关 type 属性的更多信息,请参见 § 4.2.6 高亮类型

当调用 Highlight(AbstractRange... initialRanges) 构造函数时, 运行以下步骤:
  1. highlight 成为新的 Highlight 对象。
  2. highlightpriority 设置为 0
  3. highlighttype 设置为 highlight
  4. 对于每个 rangeinitialRanges, 让 rangeArg range 转换为 ECMAScript 值的结果, 然后运行 内置类似集合的添加功能步骤, 以 highlight 作为 this 值, 并以 rangeArg 作为参数。
  5. 返回 highlight

3.2. 注册自定义高亮

为了产生效果,自定义高亮需要被注册高亮注册表中。

高亮注册表可通过 highlights 属性在 CSS 命名空间中访问, 它表示所有为自定义高亮注册的对象,适用于当前全局对象相关文档。 它是类似映射的结构,并可使用常规方法进行更新。 它的映射条目最初是空的。

如果自定义高亮 位于高亮注册表中, 则称其为已注册。 如果之后被移除,它将停止成为已注册状态。

partial namespace CSS {
  readonly attribute HighlightRegistry highlights;
};

[Exposed=Window]
interface HighlightRegistry {
  maplike<DOMString, Highlight>;
};
注册自定义高亮, 调用高亮注册表set 方法,这将运行内置类似映射设置函数的步骤, 将上下文对象作为 this 值, 传入的自定义高亮名称作为 keyArg, 传入的高亮作为 valueArg

自定义高亮注册时分配的自定义高亮名称用于在样式设置时标识高亮(参见 § 4 自定义高亮的样式设置)。

注意:在注册自定义高亮时, 建议作者使用有效的 CSS 标识符作为自定义高亮名称。 使用无效标识符可能会使高亮难以甚至无法通过 CSS 设置样式。

注意:可以为自定义高亮注册多个自定义高亮名称。 但是,使用多个名称设置一个高亮会为该高亮分配多个不同的样式集, 且无法控制这些样式集在绘制期间的冲突样式的堆叠顺序。 这可能会限制作者,并导致混乱的绘制行为 (参见下面的示例以获取更多上下文)。 因此,建议作者在样式设置时为每个高亮只使用一个名称

<style>
  div::highlight(bar) {
    color: red;
  }
  div::highlight(foo) {
    color: green;
  }
</style>
<body><div>abc</div>
<script>
  let div = document.body.firstChild;
  let r = new Range();
  r.setStart(div, 0);
  r.setEnd(div, 1);
  let h = new Highlight(r);
  CSS.highlights.set('foo', h);
  CSS.highlights.set('bar', h);
</script>

在上面的示例中, 同一个自定义高亮对象被以 foobar 两个名称注册。 由于每个样式规则都针对相同的高亮且具有相同的优先级, 作者可能期望最后一个规则在级联顺序中获胜, 并且高亮内容显示为绿色。 然而,每个高亮名称都将获得独立的一组高亮样式, 并且高亮会根据名称绘制多次。 在这种情况下,因为 foobar 之前注册, 高亮将首先用 foo 的颜色(绿色)绘制, 然后用 bar 的颜色(红色)绘制。 因此,高亮的内容将显示为红色。

4. 自定义高亮的样式设置

4.1. 自定义高亮伪元素: ::highlight()

::highlight(<custom-highlight-name>) 伪元素 (也称为自定义高亮伪元素) 表示文档中 包含部分包含在 所有范围中的已注册自定义高亮部分,并且使用了自定义高亮名称<custom-highlight-name>,如果存在的话。 <custom-highlight-name>必须是有效的 CSS <ident-token>

4.2. 处理模型

4.2.1. 适用属性

自定义高亮伪元素, 类似于内置的高亮伪元素, 只能使用有限的属性集进行样式设置。 有关完整列表,请参见 CSS 伪元素 4 § 3.2 高亮的样式设置

4.2.2. 默认样式

UA 不能在默认 UA 样式表中为自定义高亮伪元素定义任何样式。 自定义高亮伪元素继承其起源元素的样式。

4.2.3. 级联与继承

级联继承自定义高亮伪元素与内置的高亮伪元素的处理方式相同, 如 CSS 伪元素 4 § 3.5 级联与每个元素的高亮样式 中定义。

4.2.4. 绘制

自定义高亮的绘制方式与内置的高亮伪元素的绘制方式相同, 如CSS 伪元素 4 § 3.4 高亮区域CSS 伪元素 4 § 3.6 高亮的绘制中指定的, 但有以下说明:

4.2.5. 重叠高亮的优先级

自定义高亮priority 属性 定义其优先级。 该属性用于确定对应的高亮覆盖在绘制操作期间的堆叠顺序(参见 § 4.2.4 绘制)。 更高的优先级意味着在堆叠顺序中更高。 如果未显式设置其priority 属性,自定义高亮的默认数值优先级为 0。

当两个或多个自定义高亮具有相同的数值优先级时, 最后注册的高亮具有更高的有效优先级

<style>
  :root::highlight(foo) {
    color:blue;
    background-color:yellow;
  }
  :root::highlight(bar) {
    background-color:orange;
  }
</style>
<body>Some text
<script>
  let textNode = document.body.firstChild;

  let r1 = new Range();
  r1.setStart(textNode, 0);
  r1.setEnd(textNode, 6);

  let r2 = new Range();
  r2.setStart(textNode, 3);
  r2.setEnd(textNode, 9);

  let h1 = new Highlight(r1);
  let h2 = new Highlight(r2);

  CSS.highlights.set("foo", h1);
  CSS.highlights.set("bar", h2);
</script>

由于没有设置优先级 (即 h1h2 之间没有优先级差异), 自定义高亮的样式将按照插入到高亮注册表的顺序进行堆叠。 渲染结果将为 "Som" 显示为蓝色文本,黄色背景, "e t" 显示为蓝色文本,橙色背景, "ext" 显示为默认文本颜色,橙色背景。

Some text

h1.priority = 1; 设置为1将使 h1 的堆叠顺序高于 h2, 结果为 "Some t" 显示为蓝色文本,黄色背景, "ext" 显示为默认文本颜色,橙色背景。

Some text

4.2.6. 高亮类型

自定义高亮type 属性用于作者指定高亮的语义意义。 这使得辅助技术在向用户展示高亮时可以包含这些语义信息。

如果没有显式设置其type 属性,自定义高亮的默认类型将是highlight

注意:建议作者在自定义高亮用于突出显示拼写错误时,将自定义高亮type 设置为spelling-error。 当自定义高亮用于强调语法错误时,建议将其类型设置为grammar-error。 对于其他使用场景,建议将type 保持为highlight

用户代理应将自定义高亮提供给辅助技术使用。 当通过特定平台的辅助技术 API 暴露高亮时, 用户代理应尽可能具体地传达由其type 属性指定的高亮语义。

注意:例如, 如果平台的辅助技术 API 能够具体表示拼写错误和语法错误, 则期望用户代理使用这些功能来传达带有spelling-errorspelling-error的高亮的语义。 如果辅助技术 API 只能表达拼写错误, 则用户代理应使用拼写错误语义来传达拼写错误和语法错误类型的高亮。 如果辅助技术 API 无法支持表达拼写或语法错误, 则用户代理会将所有高亮暴露为通用的highlight, 而不考虑它们的实际type

注意:选择此初始类型集 是因为它们被认为是 Highlight API 的流行使用案例, 并且今天的平台辅助技术 API 已经有一些支持来表达它们的语义。 辅助技术 API 当前无法表达其他预期的 Highlight API 使用案例的特定语义。 随着辅助技术 API 逐渐支持表达 Highlight API 的更多流行使用案例, 将来可能会向HighlightType中添加更多类型。

5. 响应更改

5.1. 重绘

高亮注册表中 添加或移除自定义高亮, 或者在已注册自定义高亮中 添加或移除范围, 必须导致用户代理重新评估渲染结果,并在适当时进行重绘。

用户代理还必须根据作者对priority属性 的更改或对已注册自定义高亮范围边界点的更改, 在需要时重绘高亮。

我们应如何指定此重新评估的时间(及同步性)?[Issue #4596]

5.2. 范围更新和失效

作者可以使用RangeStaticRange 来构建自定义高亮

生成的自定义高亮表示文档的相同部分, 并且可以采用相同的样式设置。 但是,如果修改了底层文档,行为会有所不同。

Range活动范围。 用户代理会根据与该范围或其边界重叠的 DOM 更改调整Range边界点, 并相应地重绘边界点也可以由作者修改。

另一方面, 用户代理不能根据 DOM 更改调整StaticRange边界点, 也不能在创建后由作者修改。 用户代理应存储实际的StaticRange, 而不是用活动的Range 来支持它们。

更新所有Range 对象以响应 DOM 修改会带来显著的性能成本。 如果作者打算监控 DOM 更改并根据更改调整或重新创建其自定义高亮中的范围, 强烈建议使用StaticRange, 以避免这一步骤的高成本但不必要的操作。

相反,使用StaticRange 的作者应监控并响应 DOM 更改, 通过丢弃无效的范围自定义高亮并重新创建新的范围。

在计算文档的渲染方式时, 如果任何起始节点结束节点 引用的范围 其阴影包含根不属于该文档, 用户代理必须忽略该范围。 如果任何StaticRange 在关联文档的高亮注册表中无效, 用户代理也必须忽略该范围。

自定义高亮中的StaticRange[css-contain-2]的交互似乎存在问题: 在一个完全包含的元素上, 我们应期望该元素后代的 DOM 更改不会导致包含元素之外的元素失效、重新设置样式或重绘。 但是,如果静态范围的一个边界点位于包含的子树内, 而另一个边界点在子树之外, 且该子树中的 DOM 发生更改, 使得子树内的边界点不再指向有效节点, 那么整个范围应被忽略, 这将影响包含子树之外的渲染。 这是样式封装的弱点, 还是上述失效逻辑的弱点, 亦或其他问题?[Issue #4598]

6. 事件处理

事件部分待定, 基于 https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/master/highlight/events-explainer.md

自定义高亮是否应有专门的事件处理机制, 还是应该将其添加到伪元素的通用处理机制中?

附录 A. 隐私和安全考虑

本节为非规范性内容

本规范认为不会引入任何新的安全或隐私问题。 如果有人认为此结论不准确,欢迎联系 CSS 工作组或联合编辑人员。

附录 B. 致谢

本节为非规范性内容

致谢需要感谢的人员(编辑之外)。

附录 C. 变更记录

本节为非规范性内容

2020年12月8日工作草案以来的变更

除了各种编辑改进和小的调整,主要更改包括:

  • HighlightsRegister 重命名为 HighlightRegistry

  • HighlightRegistry 中移除了冗余的 add() 方法。 (见 Issue 6092)

  • 使自定义高亮覆盖层堆叠在原生高亮覆盖层下方。 (见 Issue 4595)

  • 使用整数处理高亮优先级,而不是浮点数。 (见 Issue 4592)

  • 定义高亮优先级的默认值为0。 (见 Issue 6136)

  • 将 HighlightRegistry 改为 maplike(而非 setlike),并移除 Highlight 的 name 属性。 (见 Issue 5910)

  • 澄清了来自错误窗口的范围不会被绘制。 (见 Issue 6417)

  • 指定自定义高亮没有用户代理样式。 (见 Issue 6375)

  • 推迟到[DOM]规范处理范围失效 (见 Issue 4597)

  • type 属性增加了支持不同高亮的清晰语义,以便向辅助工具暴露高亮。 (见 Issue 6498)

2020年10月22日工作草案以来的变更

2020年10月22日工作草案以来仅进行了编辑修改; 见差异

合规性

文档约定

合规性要求通过描述性断言和 RFC 2119 术语的结合来表达。关键字“MUST”(必须)、“MUST NOT”(不得)、“REQUIRED”(必需)、 “SHALL”(应)、“SHALL NOT”(不应)、“SHOULD”(应该)、“SHOULD NOT”(不应该)、“RECOMMENDED”(推荐)、“MAY”(可以)、 和“OPTIONAL”(可选)在本文件的规范部分中,应按照 RFC 2119 中的描述进行解释。 然而,为了提高可读性,这些词在本规范中并没有全部以大写字母出现。

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

本规范中的示例以“例如”开头,或使用 class="example" 与规范性文本分开显示,如下所示:

这是一个信息性示例。

信息性注释以“Note”开头,并使用 class="note" 与规范性文本分开显示,如下所示:

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

建议性部分是规范性部分,样式设计为引起特别注意,使用 <strong class="advisement"> 与其他规范性文本分开显示,如下所示: 用户代理必须提供可访问的替代方案。

合规性类别

本规范的合规性定义了三类合规性:

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

如果样式表中使用本模块定义的语法的所有语句都根据通用 CSS 语法和本模块中定义的各个功能的语法是有效的,则该样式表符合本规范。

如果渲染器除了按照适当规范解释样式表外,还正确解析并支持本规范中定义的所有功能并相应地渲染文档,则该渲染器符合本规范。然而,由于设备的限制导致用户代理无法正确渲染文档,并不会使用户代理不符合规定。(例如,用户代理不需要在单色显示器上渲染颜色。)

如果作者工具编写的样式表根据通用 CSS 语法和本模块中定义的各个功能的语法是语法正确的,并且符合本模块所描述的样式表的所有其他合规性要求,则该作者工具符合本规范。

部分实现

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

不稳定和专有功能的实现

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

非实验性实现

当规范达到候选推荐阶段时, 非实验性实现是可能的,且实现者应该发布任何已证明按规范正确实现的 CR 级别功能的无前缀实现。

为了在不同实现中建立和维持 CSS 的互操作性,CSS 工作组要求非实验性 CSS 渲染器在发布任何 CSS 功能的无前缀实现之前,向 W3C 提交实现报告(以及在必要时提交用于该实现报告的测试用例)。 提交给 W3C 的测试用例需经过 CSS 工作组的审核和修正。

有关提交测试用例和实现报告的更多信息,请参阅 CSS 工作组的网站 https://www.w3.org/Style/CSS/Test/。 如有问题,请联系public-css-testsuite@w3.org邮件列表。

索引

由本规范定义的术语

通过引用定义的术语

参考文献

规范性引用

[CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS 级联和继承 第5版. 2021年12月3日. 工作草案. URL: https://www.w3.org/TR/css-cascade-5/
[CSS-CONTAIN-2]
Tab Atkins Jr.; Florian Rivoal; Vladimir Levin. CSS 包含模块 第2版. 2020年12月16日. 工作草案. URL: https://www.w3.org/TR/css-contain-2/
[CSS-PSEUDO-4]
Daniel Glazman; Elika Etemad; Alan Stearns. CSS 伪元素模块 第4版. 2020年12月31日. 工作草案. URL: https://www.w3.org/TR/css-pseudo-4/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS 语法模块 第3版. 2019年7月16日. 候选推荐标准. URL: https://www.w3.org/TR/css-syntax-3/
[CSSOM-1]
Daniel Glazman; Emilio Cobos Álvarez. CSS 对象模型(CSSOM). 2021年8月26日. 工作草案. URL: https://www.w3.org/TR/cssom-1/
[DOM]
Anne van Kesteren. DOM 标准. 现行标准. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML 标准. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 现行标准. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. 用于RFC中的关键字以表示需求级别. 1997年3月. 当前最佳实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. 选择器 第4版. 2018年11月21日. 工作草案. URL: https://www.w3.org/TR/selectors-4/
[WebIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 现行标准. URL: https://webidl.spec.whatwg.org/

IDL 索引

enum HighlightType {
  "highlight",
  "spelling-error",
  "grammar-error"
};

[Exposed=Window]
interface Highlight {
  constructor(AbstractRange... initialRanges);
  setlike<AbstractRange>;
  attribute long priority;
  attribute HighlightType type;
};

partial namespace CSS {
  readonly attribute HighlightRegistry highlights;
};

[Exposed=Window]
interface HighlightRegistry {
  maplike<DOMString, Highlight>;
};

问题索引

我们应该如何指定此重新评估的时间(以及同步性)? [问题 #4596]
StaticRange自定义高亮 中与 [css-contain-2] 的交互似乎有问题: 在完全包含的元素上,你应该预期对该元素后代的 DOM 更改不会导致外部元素的失效和重新样式/重绘。 然而,如果静态范围有一个边界点在包含的子树内,另一个边界点在它之外,并且子树内的 DOM 更改使得内部边界点不再指向有效节点,则整个范围应被忽略,这将影响包含子树外部的绘制。 这是 样式包含 的弱点,还是上述失效逻辑的问题,或是其他原因? [问题 #4598]
关于事件的部分待定,基于 https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/master/highlight/events-explainer.md
自定义高亮是否应该有一个专用的事件处理机制,还是应该将其添加到伪元素中?
认可那些(除了编辑以外)应得功劳的人。