details[open] summary 是控制箭头旋转的唯一可靠选择器,因其精准映射 DOM 的 open 状态,兼容 JS 设置与用户交互,且需配合 display: inline、显式 transition 和 rotate(0deg)/rotate(90deg) 稳定切换。

details[open] summary 是控制箭头旋转的唯一可靠选择器,直接写 summary:hover 或 summary:active 都无法反映真实展开状态。
为什么必须用 details[open] summary 而不是伪类
浏览器原生的 summary 元素不响应 :hover 以外的交互伪类(如 :active),且用户可能通过 JS 设置 open = true,此时没有任何鼠标动作触发伪类。只有 [open] 属性是 DOM 状态的真实镜像。
-
details[open] summary匹配所有已展开面板的summary,与用户操作方式无关 -
summary::after或summary::before不能直接读取open状态,必须靠父级属性联动 - Safari 15.4+ 才支持
summary::marker,旧版 Safari 必须退回到details[open] summary::after方案
transform: rotate() 必须显式声明 transition
仅写 transform: rotate(90deg) 不会动——CSS transition 不会自动作用于未声明的属性。你得在 summary 上提前设好过渡规则:
summary {
display: inline;
transition: transform 0.2s ease;
}
details[open] summary {
transform: rotate(90deg);
}-
display: inline是必须的,summary默认是inline,但若被重置为block或flex,transform可能失效或错位 - 不要用
rotate(0deg)和rotate(90deg)做来回切换——浏览器可能因浮点精度跳帧,统一用rotate(90deg)/rotate(0deg)更稳 - 避免同时写
transition: all,它会把 margin、padding 等无关属性也加动画,导致内容区域“抖动”
隐藏原生小三角要分两步走
Chrome/Firefox 支持 summary::marker { display: none },但 Safari 15.4 以下完全不识别 ::marker。稳妥做法是双保险:
立即学习“前端免费学习笔记(深入)”;
summary {
list-style: none;
}
summary::marker {
content: "";
}
/* Safari 15.3 及更早版本 fallback */
summary::-webkit-details-marker {
display: none;
}-
list-style: none单独写无效,必须配合::marker或::-webkit-details-marker - 如果用了自定义图标(比如
summary::after { content: "▶" }),记得在details[open] summary::after里改成"▼",否则旋转和字符切换会冲突 - 某些设计系统强制重置了
all: unset,会导致summary失去默认 inline 行为,必须手动补回display: inline
真正麻烦的不是怎么转,而是怎么让旋转和内容展开动画同步——details 自身不触发 CSS transition,所以箭头转了,内容却“啪”一下弹出来。需要 JS 手动同步 max-height 动画,或者改用 grid-template-rows + subgrid 控制高度,否则视觉上永远差一拍。



















