编写定义的 CSS 名称和 shadow DOM 应该协同工作。 但是,各浏览器与规范不一致,有时 其他 CSS 名称的不一致,只是方式略有不同。
本文介绍了由作者定义的 CSS 名称的当前状态 并希望它能指导你改进 在不久的将来实现互操作性。
什么是作者定义的 CSS 名称?
作者定义的 CSS 名称是一种比较旧的 CSS 语法机制,最初
为 @keyframes
规则引入,该规则将 <keyframe-name>
定义为
自定义标识符或字符串此概念的目的是
在样式表的某个部分引用此元素,然后在另一部分引用它。
/* "fade-in" is a CSS name, representing a set of keyframes */
@keyframes fade-in {
from { opacity: 0 };
to { opacity: 1 }
}
.card {
/* "fade-in" is a reference to the above keyframes */
animation-name: fade-in;
}
其他使用 CSS 名称的 CSS 功能包括字体、属性声明 以及最近的视图转换、锚点定位和 滚动条驱动的动画效果。以下表格虽不全面,但包含名称 Chrome 检查状态时发出的所有请求
功能 | 名称声明 | 参考姓名 |
---|---|---|
关键帧 | @keyframes |
animation-name |
字体 | @font-face { }
@font-palette-values |
font-family
font-palette |
属性声明 | @property |
任何自定义属性 |
查看过渡效果 | view-transition-name
view-transition-class |
::view-transition-group() |
锚点定位 | anchor-name |
position-anchor |
滚动条驱动的动画 | animation-timeline |
view-timeline-name
scroll-timeline-name |
计数器样式 | @counter-style
Counter-reset
counter-set
counter-increment |
list-style |
容器查询 | container-name |
@container |
CSS 变量 | --something |
var(--something) |
网页 | @page |
从下表中可以看出,一个 CSS 名称通常具有对应的 CSS
reference。例如,animation-name
是对 @keyframes
的引用
名称。CSS 名称与 DOM 中定义的名称不同,例如属性
和标记名称进行声明,然后在
样式表。
名称与 shadow DOM 的关系
虽然 CSS 名称是为在内容的不同部分之间 文档或样式表,Shadow DOM 是 相反。它会封装关系,使其不会泄露 它们之间具有自己的命名空间
将 CSS 名称和 shadow DOM 结合在一起,带来 网络组件应该给人以足够的表现力,使其更加灵活,但又受到约束 足够稳定。
从理论上来说,这是很好的做法。实际上,浏览器在呈现 CSS 时 名称可与 shadow DOM 互操作,两者在同一 不同浏览器、各种浏览器以及功能和规范之间。
名称和 shadow DOM 应如何协同工作
要理解这个问题,有必要先了解一下 CSS 的这些部分, 的共同作用。
一般规则
有关 CSS 名称在影子树中行为的一般规则,请参见 CSS 范围第 1 级规范。 总结一下:CSS 名称在其定义的范围内是全局性的,这意味着 可以从后代影子树进行访问,但不能从同级的 祖先影子树。请注意,这与网络平台中的名称(如 元素 ID,这些 ID 封装在同一个树形范围内。
该规则的例外情况:@property
与其他 CSS 名称不同,CSS 属性不被 shadow DOM 封装。
相反,它们是跨不同阴影传递参数的常见方法
数据。
这样一来,
@property
描述符
特殊操作:它的行为应该类似于一个文档全局类型声明
定义了特定命名属性的作用方式。因为房源必须匹配
属性声明不匹配将产生意外的
结果,因此指定要展平和解析 @property
声明
按文档顺序排列
规则应如何与 ::part
协同运作
阴影部分
将影子树内的元素公开给其父树。这样,
父树可以访问该元素,并使用 ::part
设置其样式
元素。
由于 ::part
允许两个树范围为同一元素设置样式,因此以下代码
已指定级联顺序:
- 首先,检查阴影上下文内的样式。这是“默认” 零件的样式
- 然后,应用
::part
中定义的外部样式。这是 “自定义”零件的样式 - 然后,应用与
!important
一起定义的任何内部样式。 这样,自定义元素就可以声明特定属性的特定属性, “::part
”不可自定义。
这意味着,shadow DOM 内部的名称不能从
::part
,因为 ::part
是主机级范围的样式,而不是阴影范围的样式
样式。例如:
// inside the shadow DOM:
@keyframes fade-in {
from { opacity: 0}
}
// This shouldn't work!
// The host style shouldn't know the name "fade-in"
::part(slider) {
animation-name: fade-in;
}
规则应如何与内嵌样式配合使用
与 ::part
不同的是,内嵌样式使用 style
属性,
使用脚本以编程方式设置样式,作用域限定为元素
作用域。这是因为,要向元素应用样式,您需要
元素句柄,从而传递到影子根本身。
CSS 名称和 shadow DOM 在现实中如何协同工作
虽然上述规则定义明确且一致,但当前
则并非始终会反映这一点。
在实践中,@property
的运作方式与规范一致
并且其他大部分功能都有待解决的错误(其中部分是
尚未发布,因此有时间进行修复)。
为了测试和演示这些功能的实际运用方式,我们制作了 后续页面: https://css-names-in-the-shadow.glitch.me/. 这个网页有几个 iframe,每个 iframe 专注于一项功能,测试六个 场景:
- 对外部名称的外部引用:不涉及 shadow DOM,应执行此操作 工作。
- 对内部名称的外部引用:这种方法不可行,因为 表示在影子上下文中定义的名称已泄露。
- 对外部名称的内部引用:应该可以成功,因为树级范围的名称 由影子根继承。
- 对内部名称的内部引用:这应该有效,因为 所有引用都在同一个范围内
::part
对外部名称的引用:应该可以成功,因为::part
和名称在同一范围内声明。::part
对内部名称的引用:由于是外部作用域,因此不应起作用。 不应了解 shadow DOM 中声明的名称。
@keyframes
根据规范中的定义,您应该能够引用关键帧名称
从影子根中检索,前提是 @keyframes
at-rule 位于祖先实体中
范围。实际上,没有浏览器实施此行为,
只能在定义它们的范围内对其进行引用。请参阅
问题 10540。
@property
如规范中所定义,任何 @property
声明都将是
会被展平为文档范围不过,目前,在所有浏览器中
在文档范围内声明 @property
,并在文档范围内声明 @property
影子根会被忽略。
请参阅问题 10541。
特定于浏览器的错误
其他功能在不同浏览器中的行为不一致:
- 在 Safari 中,
@font-face
已扁平化为根范围。 - Chromium 不允许继承影子根中的
@anchor-name
规则 @scroll-timeline-name
和@view-timeline-name
的范围不正确 在::part
中(同样在 Chromium 中)。- 任何浏览器都不允许在影子根目录中声明
@font-palette-values
。 - 可以在影子根中定义
view-transition-class
(转场效果) 本身在 shadow-root 之外)。 - Firefox 允许
::part
访问内部影子名称(容器查询、 关键帧)。 - Firefox 和 Safari 不遵循影子根目录中的
@counter-style
。
请注意,counter-reset
、counter-set
、counter-increment
因为它们是隐式名称
拥有一套成熟且经过充分测试的规则。
总结
坏消息是,在检查当前互操作状态的快照时, CSS 名称和 shadow DOM 体验是不一致的, 问题。我们在这里探讨的功能 并遵守相关规范 好消息是,要使体验保持一致的增量是有限的, bug 和规范问题列表。让我们解决这个问题! 与此同时,如果您遇到了 不一致性。