最轻量、零JS、语义正确的搜索筛选区折叠方案是原生,需确保为首个子节点且不含,支持无障碍访问;不支持height过渡,可用max-height模拟滑动动画;多组互斥需监听toggle事件;“收起全部”应直接操作open属性。

用 <details></details> + <summary></summary> 快速实现搜索筛选区折叠
最轻量、零 JS、语义正确的方式就是原生 <details></details>。它天然适配搜索筛选这种“默认收起、点开查看”的场景,键盘用户按空格或回车也能触发,屏幕阅读器会自动播报状态变化。
常见错误是把 <summary></summary> 写成第二个子元素,或在它里面嵌套 <button></button> —— 这会导致点击冒泡,折叠逻辑错乱。必须确保:<summary></summary> 是 <details></details> 的第一个子节点,且内部只放纯文本或内联元素(如 <span></span>)。
-
<details></details>默认收起;加open属性可默认展开(例如筛选条件已预设时) - 浏览器不支持
height过渡,所以原生只有显隐切换,没有滑动动画 - 若需隐藏默认三角图标,用
summary::marker { content: ""; },再用summary::before补自定义箭头(注意 Safari 对::marker支持较弱,得 fallback)
需要滑动动画?用 max-height + transition 模拟
当设计要求“平滑滑出”筛选项(比如从 0px 高度展开到完整高度),就不能依赖 <details></details> 原生行为,得手动控制 max-height。
关键点在于:不能用 height: auto 做过渡(CSS 不支持),也不能用 display: none(无法过渡)。必须预估一个足够大的 max-height 值,比如 max-height: 300px,并配合 overflow: hidden。
立即学习“前端免费学习笔记(深入)”;
- 初始状态:
max-height: 0; opacity: 0; padding: 0; overflow: hidden; - 展开状态:
max-height: 300px; opacity: 1; padding: 8px 12px; - 必须加
transition: max-height 0.3s ease-in-out, opacity 0.2s, padding 0.2s,否则无动画 - 内容高度波动大时(比如筛选项数量动态增减),300px 可能不够或过大,导致动画卡顿或留白——此时需 JS 测高:
element.scrollHeight,再设为max-height
多个筛选区互斥(手风琴)?监听 toggle 事件,别用 click
搜索页常有多个筛选组(如“价格区间”“品牌”“分类”),要求点一个时其他自动收起。这时不能靠 click 监听,否则键盘用户无法触发,屏幕阅读器状态不同步。
必须监听 toggle 事件——它在用户点击、空格、回车、甚至辅助技术操作时都会触发,是唯一可信的折叠状态变更信号。
- 给所有筛选区加统一 class,比如
class="filter-group" - 监听每个
<details></details>的toggle事件,检查event.target.open === true - 只在当前项打开时,遍历其他同组
<details></details>并调用.removeAttribute('open')(别用.open = false,会再次触发toggle) - 动态插入的新筛选区,需重新绑定事件,或改用事件委托(监听父容器,再
e.target.matches('.filter-group')判断)
一键收起全部筛选?直接遍历 details 设 open = false
搜索页顶部常有“收起全部筛选”按钮,最稳做法是遍历所有 <details></details> 并显式设置 open = false。这不是模拟点击,而是直接写状态,兼容性好、无竞态、不依赖事件流。
容易忽略的是嵌套筛选结构(比如“品牌”下还有子品牌分组),document.querySelectorAll('details') 会选中全部层级,这正是你想要的——“全部收起”就该无差别操作所有节点。
- 排除固定项:加
data-no-reset属性,查询时用details:not([data-no-reset]) - 避免重复绑定:用
addEventListener而非onclick属性,方便后续解绑 - 动态加载后新增的
<details></details>,需在插入 DOM 后主动执行收起逻辑,或用MutationObserver监听 - 不要用
display: none或 CSS 类判断是否已收起——open属性才是唯一可信状态
真正难的不是怎么展开,而是展开后焦点去哪、键盘 Tab 是否跳过、屏幕阅读器念什么。这些细节没处理好,对真实用户来说,折叠功能就等于没做。



















