折叠菜单、常见问题展开收起、侧边栏导航分类,这类交互在网页里随处可见。很多刚入行的同学以为必须写JavaScript才能实现,其实html5早就给出了原生方案,那就是<details>和<summary>这对标签。而在html5还没普及的年代,html4时代的前端开发者也有自己的一套办法。这篇文章就把两种方案都讲清楚,方便你根据项目情况灵活选择。

details和summary的基本用法
<details>是一个容器标签,代表一块可以被折叠的内容区域,<summary>放在它内部,作为每次点击时显示的标题。浏览器会自动处理点击展开、再次点击收起的逻辑,完全不需要额外的脚本。来看一个最简单的例子:
<details> <summary>什么是 html5?</summary> <p>html5 是第五代超文本标记语言标准,新增了大量语义化标签和原生交互能力。</p> </details>
这段代码在页面上的表现是:默认只显示标题文字,点击标题后内容展开,再次点击则收起。整个过程由浏览器原生驱动,键盘访问、屏幕阅读器识别都没有问题,这是自己写脚本很难做周全的一点。
如果希望页面加载时内容就是展开状态,可以给<details>加上布尔属性open:
<details open> <summary>配送说明</summary> <p>默认展开的内容,用户可以点击标题手动收起。</p> </details>
还有一个容易被忽略的细节:<summary内部不要放按钮类元素,比如<button>或链接,因为<summary>本身已经承担了可点击的角色,嵌套可交互元素会导致事件冲突,语义上也不合规。另外,如果<details>里不写<summary>,浏览器会自动显示一个默认的“详细信息”文字作为标题。
样式定制与常见踩坑点
默认情况下,浏览器会在<summary>前面画一个小三角,不同浏览器的实现方式不一样。如果想自定义这个图标,需要先干掉默认样式。Chrome和Edge里可以用::-webkit-details-marker伪元素,Firefox则要用::marker,两个都写上兼容性最好:
summary {
list-style: none; /* 去掉 Firefox 默认箭头 */
cursor: pointer;
}
summary::-webkit-details-marker {
display: none; /* 去掉 Chrome 默认箭头 */
}
summary::before {
content: "+"; /* 自定义图标 */
margin-right: 8px;
display: inline-block;
}
details[open] summary::before {
content: "-";
}第二个常见需求是展开收起的动画效果。很遗憾,<details>的高度变化本身不能直接用transition过渡,因为浏览器切换的是显示状态而不是数值属性。目前比较流行的做法是借助JavaScript监听toggle事件,配合动画库补间高度;如果只是想要淡入效果,也可以对内容区的opacity做过渡。
还有一个坑值得提醒:<summary>必须是<details>的第一个子元素,中间不能插入其他内容,否则浏览器不会把它识别为标题,折叠交互就会失效。此外<summary>默认是display: list-item,改成display: flex时记得加上list-style: none,不然小三角又会冒出来。
html4时代是怎么做折叠菜单的
在html5标签出现之前,折叠效果全靠JavaScript操作DOM。思路很直接:准备一个标题节点和一个内容节点,点击标题时判断内容节点的display属性,是none就改成block,反之亦然:
<div class="item">
<div class="title" onclick="toggle(this)">点击展开</div>
<div class="content" style="display:none">折叠的内容</div>
</div>
<script type="text/javascript">
function toggle(el) {
var content = el.parentNode.getElementsByTagName('div')[1];
content.style.display =
content.style.display === 'none' ? 'block' : 'none';
}
</script>这套方案当年几乎 everywhere,后来jQuery流行起来,大家更习惯用slideToggle()一行代码搞定,还自带滑动动画。老项目的维护者对这写法应该非常熟悉。它的优点是完全可控,动画、互斥展开、手风琴模式都能自由实现;缺点也很明显:需要写脚本、依赖事件绑定,无障碍属性得自己手动补aria-expanded之类的状态,出bug的概率也更高。
对比一下两种方案的适用场景:如果只是简单的内容展开收起,比如FAQ列表、设置面板、商品详情说明,直接用<details>和<summary>,代码干净、语义清晰、天然支持无障碍;如果需求复杂,比如多个面板互斥展开、需要复杂的动画编排、要在移动端做手势控制,那还是老老实实用JavaScript自己控制状态更灵活。两者并不冲突,实际项目里经常混用,简单模块用原生标签,复杂交互区域用脚本驱动,各取所长。
details和summary折叠菜单html5折叠修改时间:2026-09-05 11:54:37