details标签仅控制展开/收起,不参与搜索过滤;真正起作用的是checkbox的name/value与列表项data属性严格对应,配合JS或CSS选择器实现筛选。

details 标签本身不支持搜索过滤,但能简化筛选区结构
details 是纯展示控制标签,它只管“展开/收起”,不参与数据匹配或 DOM 过滤。很多人误以为给 details 加个 data-filter="xxx" 就能联动搜索,结果发现勾选 checkbox 后内容该显示还显示、该隐藏还隐藏——根本没反应。
真正起作用的是:checkbox 的 name 和 value 必须与目标列表项的 data-* 属性严格对应;而 details 只负责把“语言”“状态”这些筛选维度包得干净、可访问、不用写 JS 控制开合状态。
常见错误现象:
- 用
div+onclick模拟折叠,结果键盘无法触发、屏幕阅读器读不出状态 - 给
details设了display: none,导致它完全从可访问性树中消失 - summary 里写了“已选 2 项”,但没用 JS 更新数字,用户看到的是过期计数
checkbox 的 name/value 必须映射到 data 属性才能触发过滤
过滤逻辑靠的是 CSS 兄弟选择器或 JS 的 querySelectorAll 批量匹配,不是靠 details 自己。所以每个 input[type="checkbox"] 的 value 得是目标元素上实际存在的 data- 值。
立即学习“前端免费学习笔记(深入)”;
例如:
- 筛选项:
<input type="checkbox" name="language" value="python"> - 列表项:
<li data-language="python">Python 教程</li> - 这样 JS 才能用
document.querySelectorAll('li[data-language="python"]')找到对应节点
如果 value 写成 "py" 或 "Python"(大小写不一致),或者列表项用的是 data-lang 而不是 data-language,过滤就失效。
性能提示:别在每次输入都重新遍历全部列表项。缓存原始数据数组,用 filter() 计算可见项,再批量切换 hidden 属性,比反复查 DOM 快得多。
用 hidden 属性控制显隐,别用 display: none
hidden 是 HTML5 原生布尔属性,语义明确、可被屏幕阅读器识别、且不会破坏 flex/grid 布局流。而 display: none 会让元素彻底脱离渲染树,某些动画或 JS 获取 offsetHeight 时会出错。
实操建议:
- 初始状态统一加
hidden,JS 根据筛选条件增删该属性 - 不要给
hidden写 CSS 覆盖(如[hidden] { display: block !important; }),这会破坏语义 - 配合
:not([hidden])在 CSS 中微调可见项样式,比如加 border-top
注意:IE 不支持 hidden,如需兼容,可用 class 替代,但必须同步维护 aria-hidden 和 tabindex。
JS 只需监听 checkbox change 和 input keyup,其余交给 HTML 语义
核心逻辑就两件事:收集当前所有勾选的值,然后遍历列表项,看它的 data-* 是否在勾选集合里。不需要操作 details.open,也不需要手动 toggle class。
示例关键片段:
const filters = { language: [], status: [] };
document.querySelectorAll('input[type="checkbox"]:checked').forEach(cb => {
filters[cb.name].push(cb.value);
});
document.querySelectorAll('li').forEach(item => {
const matchLang = !filters.language.length || filters.language.includes(item.dataset.language);
const matchStatus = !filters.status.length || filters.status.includes(item.dataset.status);
item.hidden = !(matchLang && matchStatus);
});
容易被忽略的一点:移动端点击 checkbox 有时会触发两次 change(尤其在 label 包裹不完整时),建议用 event.target.checked 判断真实状态,而不是依赖 change 事件本身是否发生。



















