你以为 details/select/dialog 打开状态只能靠 JS 监听?今天 :open 一个伪类把这件事彻底原生化了

写过表单的人都踩过这个坑——每次想给 details 展开、select 打开、dialog 弹出时加点样式,都要靠 JS 监听状态变化,再联动 class,一套下来几十行。今天这件事被一个伪类彻底原生化了。

:open 是 Selectors Level 4 新出的伪类,专门匹配「当前处于打开状态」的元素。哪些元素有打开状态?details(展开/折叠)、select(下拉打开)、dialog(弹窗显示)、input(日期/颜色选择器等 picker)。一个选择器全覆盖,不需要属性选择器,不需要 JS。

基础用法三行替代几十行 JS。details 展开时让 summary 变蓝:

details:open > summary {
  color: #2563eb;
  font-weight: bold;
}

select 打开时背景变亮、箭头翻转:

select:open {
  background-color: #f8f2dc;
}

select:open ~ .arrow {
  transform: rotate(180deg);
}

dialog 弹窗打开时加动画入场:

@starting-style {
  dialog:open { opacity: 0; }
}

dialog:open {
  animation: fade-in 0.3s ease;
}

你可能说这和 [open] 属性选择器有什么区别?区别大了。[open] 匹配的是元素有没有这个属性,:open 匹配的是元素的语义状态。select 打开时的 picker 界面没有 open 属性,但 :open 能匹配;dialog 用 show() 打开时元素有 open 属性,但用 showModal() 打开时 :modal 比 :open 更精确。三套选择器各司其职。

浏览器支持方面,Chrome 133/Firefox 136/Safari 26.5 全部支持,2026 年 2 月进 Baseline,全球覆盖约 85%。渐进增强写法:

@supports not selector(:open) {
  details[open] > summary { /* fallback */ }
}

下一个可落地的事:打开任意一个带 details 的页面,F12 试一条 details:open { border-color: var(--brand); },你会发现展开内容的那一刻样式自己变了,不需要任何 JS。

评论区

0 条评论

登录后可评论。