网络平台上“自定义”功能的数量正在不断增加。我们有自定义属性 (--my-property
)、自定义元素 (<my-element>
) 和自定义事件 (new CustomEvent('myEvent')
)。在某个时刻,我们甚至可能会获得 自定义媒体查询 (@media (--my-media)
)。
但这还不是全部!您可能错过了它,因为它没有在 Google 的 “Chrome 90 新功能” 文章中提及(公平地说,声明式 Shadow DOM 在此版本中抢尽风头),但 Chrome 刚刚添加了对另一种“自定义”功能的支持:自定义状态伪类 (:--my-state
)。
内置状态
在讨论自定义状态之前,让我们快速了解一下为内置 HTML 元素定义的内置状态。 CSS 选择器模块 和 HTML 标准的 “伪类”部分 指定了许多可用于匹配不同状态下元素的伪类。以下伪类在当今的浏览器中都得到了广泛的支持
用户操作 | |
---|---|
:hover |
鼠标光标悬停在元素上 |
:active |
用户正在激活元素 |
:focus |
元素具有焦点 |
:focus-within |
元素具有或包含焦点 |
位置 | |
:visited |
用户已访问过链接 |
:target |
元素是页面 URL 片段的目标 |
输入 | |
:disabled |
表单元素已禁用 |
:placeholder-shown |
输入元素显示占位符文本 |
:checked |
复选框或单选按钮已选中 |
:invalid |
表单元素的值无效 |
:out-of-range |
输入元素的值在 指定范围之外 |
:-webkit-autofill |
浏览器已自动填充输入元素 |
其他 | |
:defined |
自定义元素已注册 |
注意:为简洁起见,省略了一些伪类,并且某些描述没有提及所有可能的用例。
自定义状态
与内置元素类似,自定义元素也可以具有不同的状态。使用自定义元素的网页可能希望为这些状态设置样式。自定义元素可以通过其宿主元素上的 CSS 类 (class
属性) 公开其状态,但这被 认为是一种反模式。
Chrome 现在支持用于向自定义元素添加内部状态的 API。这些自定义状态通过自定义状态伪类公开给外部页面。例如,使用 <live-score>
元素的页面可以为该元素的自定义 --loading
状态声明样式。
live-score {
/* default styles for this element */
}
live-score:--loading {
/* styles for when new content is loading */
}
<labeled-checkbox>
元素添加 --checked
状态
让我们向 自定义状态伪类 规范包含一个完整的代码示例,我将使用它来解释 API。此功能的 JavaScript 部分位于自定义元素的类定义中。在构造函数中,为自定义元素创建了一个“元素内部”对象。然后,可以在内部 states
对象上设置和取消设置自定义状态。
请注意,ElementInternals
API 确保自定义状态对于外部是 只读的。换句话说,外部页面无法修改自定义元素的内部状态。
class LabeledCheckbox extends HTMLElement {
constructor() {
super();
// 1. instantiate the element’s “internals”
this._internals = this.attachInternals();
// (other code)
}
// 2. toggle a custom state
set checked(flag) {
if (flag) {
this._internals.states.add("--checked");
} else {
this._internals.states.delete("--checked");
}
}
// (other code)
}
网页现在可以通过相同名称的自定义伪类为自定义元素的内部状态设置样式。在我们的示例中,--checked
状态通过 :--checked
伪类公开。
labeled-checkbox {
/* styles for the default state */
}
labeled-checkbox:--checked {
/* styles for the --checked state */
}
此功能尚未成为标准
浏览器供应商在过去 三年 中一直在讨论如何通过自定义伪类公开自定义元素的内部状态。Google 的 自定义状态伪类 规范仍然是 WICG 托管的“非正式草案”。该功能在 W3C TAG 进行了 设计审查,并已 移交给 CSS 工作组。在 Chrome 的“发布意图”讨论中,Mounir Lamouri 写道
看起来此功能得到了良好的支持。听起来,只要它没有得到广泛发布,网页开发人员就很难从中受益,但希望 Firefox 和 Safari 也会遵循并实现它。必须有人首先实现它,并且鉴于没有预见的向后不兼容的更改,因此先走一步似乎是安全的。
现在我们必须等待 Firefox 和 Safari 中的实现。浏览器错误已提交 (Mozilla #1588763 和 WebKit #215911),但尚未引起太多关注。
不幸的是,这再次只是我们问题的半成品解决方案。
我这里的主要问题是它与 Shadow Root 密切耦合,并且您只能使宿主元素(而不是其特定子元素)具有状态。
考虑以下问题
您有一个滑块,此滑块生成一个分页列表,在此列表中有多个列表项,并且每个列表项中都有一个按钮。
现在您想标记此项:–selected,以便用户可以相应地设置所选项目内按钮的样式。不幸的是,使用自定义伪状态(因为它绑定到您的滑块)或自定义伪元素(即:
part
属性)(因为它不允许位置选择器)都无法实现。我们非常接近有用的东西……