details[open] summary::after 是唯一稳定跨浏览器的选择器,需同时定义未展开和展开样式并添加 transition 和显式 transform,避免 safari 渲染闪烁。

details[open] 选择器必须用对
默认展开的 <details open></details>,CSS 要让箭头初始就旋转到位,不能靠 JS 延迟设置,也不能指望伪元素自己“感知”状态。唯一可靠方式是用属性选择器 details[open] summary::after 直接匹配已存在的 open 属性。
常见错误是只写 summary::after 设旋转,结果默认展开时箭头还是收起态;或者误用 :has(> summary:is([open])) —— 这个选择器目前(2026年8月)在 Safari 和部分旧版 Chrome 中不支持,且 <summary></summary> 本身没有 open 属性。
-
details[open] summary::after是唯一稳定、跨浏览器生效的选择器 - 必须同时定义未展开和展开两套样式,否则初始态缺失
- 别漏掉
transition: transform 0.2s ease,否则旋转会突变
summary::after 箭头初始态要手动设 transform
伪元素 ::after 默认不带旋转,即使父级 <details></details> 已有 open 属性,也得显式写 transform: rotate(90deg) 才能匹配展开方向。
典型配置如下:
summary::after {
content: "▶";
display: inline-block;
transition: transform 0.2s ease;
}
details[open] summary::after {
transform: rotate(90deg);
}
- 箭头字符建议用 Unicode(如 ▶ / ▼ / ➤),比 border 三角更轻量、无重排风险
- 如果用 SVG 或背景图,
transform-origin必须设为center,否则旋转中心偏移 - 别在
summary上设display: block,否则::after可能换行或失焦
隐藏原生 marker 的兼容性坑
Chrome/Firefox 可用 summary::marker { display: none; } 干净移除小三角,但 Safari ≤15.4 不支持 ::marker,得 fallback 到 list-style: none。
所以完整写法要兼顾:
summary {
list-style: none;
}
summary::marker {
display: none;
}
/* Safari 15.4 及以下靠上面 list-style 生效 */
-
list-style: none对所有浏览器都有效,但无法单独控制 marker 内容 -
::marker在 Safari 16+ 和 Chrome 90+ 才稳定,生产环境必须双写 - 别用
appearance: none—— 它会破坏键盘焦点轮廓线,损害可访问性
初始展开时动画不触发,这是正常行为
toggle 事件只在用户交互或 JS 修改 open 时触发,页面加载时已有 open 属性,不会触发任何事件,CSS 旋转自然也不走过渡动画 —— 这不是 bug,是规范行为。
如果你非要“默认展开也带入场动画”,只能用 JS 在 DOMContentLoaded 后强制重置一次:details.open = false 再立刻设回 true,但会多一次 DOM 重排,且屏幕阅读器可能播报两次。绝大多数场景下,直接静态显示旋转后的箭头更合理。
真正容易被忽略的是:Safari 对 details[open] summary::after 的解析有时延迟一帧,尤其在首屏渲染快的设备上,可能看到箭头先闪一下再转 —— 加 will-change: transform 能缓解,但别滥用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











