原生 HTML 的 details 元素配合 summary 可实现无 JS 待办清单折叠功能,summary 为唯一可点击标题,内容直跟其后;需避免嵌套、正确监听 checkbox change 更新计数,用 max-height 模拟展开动画,并注意 pointer-events 和 Safari 兼容性问题。

用 details 和 summary 最快实现折叠待办清单
不用写 JS,不引入框架,原生 HTML 就能做可折叠的待办任务列表——关键就是 details 元素。它自带展开/收起状态和语义化,浏览器原生支持(Chrome 12+、Firefox 49+、Safari 6.1+ 都 OK),连过渡动画都不用额外加。
常见错误是把 details 当成普通容器乱套 div,结果点不动或样式错乱。记住:必须且只能有一个 summary 子元素作为触发标题,其余内容直接跟在后面。
<details><summary>今日待办(3项)</summary><ul>
<li>发周报</li>
<li>Review PR #42</li>
<li>更新文档 README.md</li>
</ul></details>
-
summary内容会自动变成可点击区域,带小箭头图标(不同浏览器样式略有差异) - 默认是收起状态;加
open属性可默认展开: - 不能嵌套
details(部分浏览器不渲染内层控件),如需多级折叠,得用 JS 模拟
让折叠项支持勾选状态并联动显示数量
原生 details 不感知内部表单状态,所以“完成 2/3”这种动态计数得靠 JS 监听 change 事件手动更新 summary 文本。重点不是绑定 click,而是监听 checkbox 的 change,避免重复触发。
使用场景:用户勾选后立刻更新标题里的数字,同时保持折叠态不变(不因点击 checkbox 而意外展开/收起)。
<details id="todo-list"><summary>今日待办(<span id="done-count">0</span>/3)</summary><ul>
<li>
<input type="checkbox"> 发周报</li>
<li>
<input type="checkbox"> Review PR #42</li>
<li>
<input type="checkbox"> 更新文档 README.md</li>
</ul></details>
- 给
details加id方便获取,用querySelectorAll('input[type="checkbox"]')统一监听 - 不要用
click事件——移动端双击缩放或 checkbox 样式覆盖时可能失效;change更可靠 - 更新
summary时,只改span内容,别重写整个summary.innerHTML,否则会丢失原生箭头图标
折叠动画不生效?CSS 过渡要绕开 details 的 display 切换
details 展开收起本质是 display: block/none 切换,无法直接对 height 做 CSS 过渡。强行加 transition: height .3s 没用,因为 height 从 auto 变到具体值时浏览器无法插值。
解决方法是用 max-height + overflow: hidden 模拟,但必须预估最大高度(比如设成 max-height: 500px),否则过渡会卡顿或跳变。
- 给
details内部内容容器(如ul)加类: - CSS 中写:
.todo-items { max-height: 0; overflow: hidden; transition: max-height .25s ease-out; } - 再用 JS 在
toggle事件里切换类:el.addEventListener('toggle', () => el.querySelector('.todo-items').classList.toggle('expanded')),配合.expanded { max-height: 500px; } - 缺点:需要预设足够大的
max-height,内容超长时仍会截断;iOS Safari 对max-height过渡支持不稳定
移动端点击无响应?检查是否被 pointer-events 或 z-index 干扰
某些 UI 框架(如 Tailwind 的 pointer-events-none)或自定义 CSS(比如父容器 z-index: -1)会让 summary 失去点击能力,表现为点击没反应、箭头不翻转。这不是 bug,是层叠上下文或事件捕获被阻断了。
- 用浏览器开发者工具检查
summary元素:确认 computed 样式中pointer-events是auto,且没有父级设置了pointer-events: none - 检查
summary是否被其他绝对定位元素(如遮罩层、广告 banner)盖住;临时加outline: 2px solid red看是否真被遮挡 - Safari iOS 15.4+ 有已知问题:如果
summary里包含button或input,可能导致整个控件失活;此时应避免在summary内放交互元素,把操作移到展开后的内容区
真正麻烦的不是怎么写,而是细节叠加后的表现不一致:比如在 Safari 里加了 max-height 动画,又用了 Tailwind 的 group 类控制 icon 旋转,再遇上 checkbox 的 accent-color 自定义——这些组合容易互相覆盖。先确保基础功能跑通,再一层层加修饰。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











