语义化多级导航应使用 ul/li 嵌套结构,子 ul 必须置于父 li 内部;推荐 base href 统一路径管理;动态场景优先用 JSON+JS 渲染,兼顾可访问性与可维护性。

用 ul 和 li 嵌套实现语义化多级导航
HTML 本身不提供“目录导航组件”,但用标准的 ul/li 嵌套就能清晰表达层级关系,浏览器和屏幕阅读器都能正确识别。关键不是“怎么画出菜单样式”,而是“怎么组织结构让逻辑可读、可维护、可访问”。
常见错误是直接用 div 堆叠或靠 CSS 伪类生成箭头/缩进,结果 HTML 结构扁平、无嵌套,JS 动态展开时也难定位父级。
- 一级菜单项用
li包裹a,二级及以下菜单作为该li的子ul - 每个子
ul必须放在父li内部(不是同级div或后面追加),否则语义断裂 - 避免给
ul设display: none后再 JS 控制显隐——这会让初始 HTML 不可访问;应配合aria-expanded和aria-hidden管理状态
用 details/summary 快速实现原生折叠(适合静态小目录)
如果只是展示本地文档结构、不需要兼容 IE 或复杂交互,details 是最轻量的选择:无需 JS、自带键盘支持(空格/回车展开)、默认可访问性良好。
但它不支持多层嵌套的“全开/全关”联动,且样式定制受限(比如无法让 summary 左侧加图标而不影响语义)。
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
-
details可以嵌套,但二级details必须写在一级summary的内容中,不能放在details外部 - 不要用
details[open]强制默认展开所有——用户可能只需要看某一层,过度展开反而增加认知负担 - 若需 hover 展开(非点击),必须额外加 JS,因为
details不响应 hover
<details>
<summary>前端</summary>
<details>
<summary>JavaScript</summary>
<p><a href="js/basics.html">基础语法</a></p>
</details>
</details>
路径处理:用相对路径还是 <base href>?
多级目录下,a 标签的 href 容易写错,尤其是从 /docs/guide/index.html 跳转到 /docs/api/core.html 时,相对路径要写成 ../../api/core.html,极易出错。
- 推荐在
head中加<base href="/docs/">(注意结尾斜杠),所有href就统一用根路径写法,如href="guide/intro.html" - 不要用
<base href="./">或<base href="">—— 这会导致路径解析不稳定,尤其在服务端渲染或静态托管时行为不一致 - 如果站点部署在子路径(如
https://example.com/myapp/),base href必须精确匹配该路径,否则所有链接 404
动态生成导航时,为什么 fetch() 读 JSON 比硬编码更可靠?
当目录结构超过 5 级或常变动时,把导航数据写死在 HTML 里会迅速失控。用外部 JSON 描述结构,再用 JS 渲染,能解耦内容与模板,也方便后端注入或 CI 自动生成。
但要注意:JSON 数据必须和实际文件路径严格一致,否则 404;且首次渲染依赖 JS,SEO 和无 JS 环境下会丢失导航。
- JSON 示例结构应包含
title、path、children字段,避免用url或link这类易歧义的键名 - 渲染函数递归调用时,检查
children?.length是否存在且 > 0,再决定是否渲染子ul,防止空数组报错 - 不要在
DOMContentLoaded里直接fetch并innerHTML = ...—— 这会清空原有 DOM 事件绑定;应插入到指定容器节点内
真正难的不是写出三级菜单,而是当新增一个 /blog/2024/deep-dive-web-components/ 目录时,不用改 HTML、不漏更新面包屑、不破坏已有锚点跳转——这些都靠结构设计前置决定。

















