CSS 选择样式的继承更改

Stephen Chenney
Stephen Chenney

发布时间:2024 年 10 月 8 日

从 Chrome 131 开始,::selection::target-text 伪类的 CSS 突出显示继承将发生变化。这是为了创建一个更直观的继承模型,并与最近添加的 ::highlight::spelling-error::grammar-error 伪类保持一致。本文介绍了此次变更,这项变更对大多数网站应该不会产生明显影响。

选择样式

为所选文本设置样式可以向用户传达含义,例如所选内容的用途或无法选择文本。例如,GitHub 会以与所选目录结构不同的颜色显示所选代码。

CSS 支持使用 ::selection 伪元素(一组称为“突出显示伪元素”的伪元素之一)设置选择样式。这些伪元素用于控制文本在各种用户、浏览器或脚本驱动操作下的显示方式。除了选择之外,您还可以设置拼写错误 (::spelling-error)、语法错误 (::grammar-error)、嵌入网址的文本目标 (::target-text) 和脚本生成的突出显示内容 (::highlight) 的样式。

与任何 CSS 属性集一样,在设计网站时,继承行为是一项重要考虑因素。通常,开发者希望 CSS 属性要么通过 DOM 元素树继承(例如 font),要么根本不继承(例如 background)。

Chrome 131 中选择行为的变更

请考虑以下文档片段:

p {
  color: red;
}

.blue::selection {
  color: blue;
}
<p class="blue">Some <em>emphasized</em> text that one would expect to be blue</p>

fragment 的样式声明会修改所选文本的颜色,其中一个规则与所有元素匹配,另一个规则与类 "blue" 的元素匹配。在 Chrome 130 或更低版本中选择此选项时,会出现以下结果:

您可能预期为蓝色的文本显示为红色。

在 Chrome 131 中选择此选项后,结果会更改为:

文本现在以蓝色突出显示。

有哪些变化?选择属性的继承行为过去一直是通过起源元素继承实现的,其中选择会使用与所选元素匹配的 ::selection 中的属性。Chrome 130 及更低版本使用此模型,其中强调文本没有匹配的 ::selection,因为 .blue::selection 仅与具有 "blue" 类的元素匹配,而 <em> 元素缺少此类。

Chrome 131 启用了新行为,即元素会从其父元素继承选择行为。在上面的示例中,<em> 元素没有与其匹配的 ::selection,因此它会继承 <p> 元素的选择颜色。这称为 CSS 突出显示继承,您可以在较低版本的 Chrome 中试用此功能,只需在 chrome://flags 中启用实验性 Web 平台功能即可。

依赖于不继承的选择属性的网站可能会看到所选文本的外观发生变化,但 bug 报告中的证据表明,这种行为的用例很少。

用于选择的 CSS 自定义属性仍然有效

许多网站通过使用 CSS 自定义属性来模拟 CSS 突出显示继承。自定义属性会通过元素树进行继承,通过如下代码段可获得“继承自父级”结果:

:root {
   --selection-color: lightgreen;
}

::selection {
  color: var(--selection-color);
}

.blue {
  --selection-color: blue;
}
<p>Some <em>emphasized</em> text</p>
<p class="blue">Some <em>emphasized</em> text that is blue</p>

在 Chrome 130 和 131 中同时选择此选项时,会出现以下结果:

第一条线为绿色,第二条线为蓝色。

在这里,每个元素都会通过元素树继承 --selection-color 属性的某个值,并且在选择文本时会使用此颜色。具有 .blue 类的元素及其子元素在选中后会显示为蓝色,其他元素则显示为浅绿色。许多网站都使用此方法,Stack Overflow 也推荐使用此方法。

为了保持兼容性,CSS 突出显示继承模型指定 ::selection(以及其他 CSS 突出显示伪元素)会从其来源元素(应用于它们的元素)继承自定义属性值。使用此方法的网站应该不会受到 Chrome 131 中的更改影响。

系统会忽略在 ::selection 伪元素本身上定义的自定义属性,以避免出现竞争性的继承行为。您必须在元素本身上定义这些属性,然后在伪元素中引用它们。

适用于 ::selection 的通用选择器会停用突出显示继承

不使用 CSS 自定义属性的网站可能使用通用选择器来设置所选文字的颜色。例如,如下 CSS:

::selection /* = *::selection (universal) */ {
  color: lightgreen;
}

.blue::selection {
  color: blue;
}
<p>Some <em>emphasized</em> text</p>
<p class="blue">Some <em>emphasized</em> text</p>

在 Chrome 130(及更低版本)和 Chrome 131(及更高版本)中同时选择此选项时,会出现以下结果:

第一行文字显示为绿色。第二个是蓝色,但强调的字词是绿色。

CSS 突出显示继承不会导致第二个强调文本从其父元素继承蓝色,因为通用选择器与 <em> 元素匹配,并应用通用突出显示颜色(浅绿色)。

如需获享 CSS 突出显示继承的好处,请将通用选择器更改为仅匹配根元素,然后由其子元素继承:

:root::selection {
  color: lightgreen;
}

.blue::selection {
  color: blue;
}
<p>Some <em>emphasized</em> text</p>
<p class="blue">Some <em>emphasized</em> text</p>

Chrome 131 中的结果如下所示:

第一行文字显示为绿色。第二行是蓝色的。

如果您的网站修改了选择颜色,但未使用自定义属性,则可能是因为您为 ::selection 伪元素使用了通用选择器。好消息是,您的网站不会因 Chrome 中的这项变更而中断,但您将无法获得突出显示继承带来的任何人体工学优势。

::target-text 样式也将发生变化

本文中所述的所有行为和更改都适用于 ::target-text 伪元素,也适用于 ::selection。在单个网站上设置多个目标文本样式的用例有限,而且该功能非常新,因此您的网站的 ::target-text 行为不太可能发生变化。

此次变更的原因是什么?

在开发其他突出显示伪元素时,CSS 工作组决定使用突出显示继承模型实现继承。这已经是 ::selection 伪元素规范中的方法,但浏览器并未实现它。非选择伪元素使用突出显示继承,其中伪元素的继承方式就像是属性一样。也就是说,元素会从其文档父元素继承突出显示伪元素。

为了确保所有突出显示伪元素保持一致,CSS 工作组重申了对 ::selection 突出显示继承的支持,浏览器正在努力推出新行为,同时尽量避免破坏现有网站。

试试看

以下 CodePen 演示了这些更改。在 Chrome 131 中试用。