应使用实现协议折叠,因其原生支持可访问性、键盘导航和屏幕阅读器识别,而div+onclick或JS控制display会违反无障碍规范。

直接用 <details></details> + <summary></summary> 就行,这是目前唯一既合规又省事的方案。 法律要求协议必须“可访问、可复制、可存档”,PDF 或图片不满足;而手写 JS 控制 display 或 max-height 会破坏键盘导航和屏幕阅读器识别,属于无障碍违规。
为什么不能用 div + onclick 实现协议折叠?
常见错误是写一个 <div class="toggle">用户协议</div>,再绑 onclick 切换内容显隐。这会导致:
- 键盘用户按
Tab进不去、按Space/Enter触发不了 ——<div> 默认不可聚焦、无语义 <li>屏幕阅读器读不出“该区域当前是否展开”,因为没自动加 <code>aria-expanded - 焦点不会自动跳进协议内容区,用户得手动按十几次
Tab才能开始阅读 - 协议滚动时若全局设了
scroll-behavior: smooth,会卡顿甚至失焦(尤其 iOS) -
<summary></summary>必须是<details></details>的第一个子元素,否则点击无效 - 协议正文用
<div class="terms-content"> 包裹,并单独设 <code>scroll-behavior: auto,避免滚动卡顿 - 需要默认展开(比如注册页强制阅读),就加
open属性:<details open></details> - 弹出后要确保焦点落在协议内首个可聚焦元素(如同意复选框),可用
document.querySelector('.terms-content input').focus()补一手
怎么用 <details></details> 正确展示协议内容?
原生标签自带合规保障,只需注意三点:
示例结构:
立即学习“前端免费学习笔记(深入)”;
<details open>
<summary>用户协议与隐私政策</summary>
<div class="terms-content">
<p>本协议由……</p>
<input type="checkbox" id="agree"> <label for="agree">我已阅读并同意</label>
</div>
</details>
自定义样式时最容易踩的坑
可以改颜色、字体、加图标,但以下操作会直接破坏可访问性:
- 给
<summary></summary>设display: flex或float→ 导致::marker位置错乱或消失 - 用
summary::marker { display: none }后没补图标 → 用户看不到任何视觉反馈 - 在 Safari 中只靠
summary::marker改箭头 → 它根本不支持,必须用summary::before+transform: rotate() - 给
<details></details>加transition: height 0.3s→ 高度是动态计算的,过渡无效,还会抖动
安全做法:用 details[open] summary::before 控制旋转动画,同时保留原生交互逻辑。
真正麻烦的不是折叠本身,而是协议内容过长时的滚动体验和焦点管理——这两点原生 <details></details> 不管,得你手动补上 scroll-behavior: auto 和 .focus() 调用,否则移动端用户可能根本滑不到底部就放弃了。



















