现代浏览器可用details+summary实现手风琴,语义正确且无障碍友好;兼容ie/旧edge需js+aria-expanded+hidden;动态内容用事件委托;动画推荐scrollheight+height过渡而非max-height。

手风琴用 details 元素最省事,但兼容性有坑
现代浏览器(Chrome 12+、Firefox 49+、Safari 6.1+)原生支持 details + summary 实现手风琴,无需 JS,语义正确,还自带焦点和键盘支持(空格/回车展开收起)。但 IE 完全不支持,Edge 18 及更早版本也不行。
如果项目需兼容 IE 或旧 Edge,必须降级为 div + JS 控制 aria-expanded 和 class 切换;否则直接上 details 是最快最健壮的选择。
-
details默认可聚焦,按 Tab 进入后,空格/回车即可切换,无障碍友好 - 不能用 CSS 伪类
::before覆盖summary的默认箭头(部分浏览器会忽略),要用list-style: none+ 自定义图标 - 想默认展开?加
open属性:<details open><summary>标题</summary>内容</details>
用 JS 手动实现时,aria-expanded 和 hidden 必须同步更新
手动控制手风琴状态时,只切 class 或只改 display 样式是不够的。屏幕阅读器依赖 aria-expanded 判断当前状态,而 hidden 属性比 display: none 更可靠地隐藏语义内容(尤其对辅助技术)。
错误写法:el.style.display = 'none' 后没设 el.setAttribute('aria-expanded', 'false') —— 这会让读屏软件“看到”按钮说“已展开”,但内容却不可见。
- 每次点击标题,先查当前
aria-expanded值,再反向设置 - 内容容器建议同时用
hidden属性和 CSS 控制可见性:content.hidden = !isOpen+[hidden] { display: none; } - 避免用
visibility: hidden或opacity: 0隐藏内容——它们仍会被读屏软件解析
多个手风琴项共存时,别用 querySelectorAll('.accordion-item') 硬绑事件
静态绑定所有 .accordion-item 的 click 事件看似简单,但遇到动态插入新项(比如 AJAX 加载内容后追加)就会失效。更稳的方式是事件委托到父容器。
假设父容器有 id="faq-accordion",标题元素是 .accordion-header:
document.getElementById('faq-accordion').addEventListener('click', (e) => {
const header = e.target.closest('.accordion-header');
if (!header) return;
const item = header.parentElement;
const content = item.querySelector('.accordion-content');
const isOpen = content.hidden;
content.hidden = !isOpen;
header.setAttribute('aria-expanded', !isOpen);
});
-
closest()能安全捕获嵌套在标题内的图标或文字子元素的点击 - 不用给每个 header 单独加事件监听器,内存和性能更优
- 注意:如果手风琴需要「单开」(即展开一个时自动关闭其他),得在 toggle 前遍历并收起其余
.accordion-content
CSS 动画收起展开时,max-height 是常见但脆弱的方案
想加过渡效果?很多人用 max-height + transition,但必须设一个“足够大又不太大”的值(比如 max-height: 500px),否则动画卡顿或截断内容。它本质是 hack,不是真正基于内容高度的动画。
更可靠的方案是用 height: auto + scrollHeight 计算真实高度,再通过 JS 设置内联 style.height 并触发 transition:
- 展开前先设
el.style.height = '0',强制重排 - 再设
el.style.height = el.scrollHeight + 'px',触发动画 - 收起时监听
transitionend,结束后设el.style.height = ''回退到 auto - 若内容含图片或字体加载中,
scrollHeight可能不准,需等load或fontloaded后重新测量
aria-expanded 和 hidden 的配对更新,以及 scrollHeight 测量时机,这两处最容易漏掉。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











