面包屑导航必须用<nav aria-label="Breadcrumb">包裹<ol>,各级用<li>,当前页用<li aria-current="page">,分隔符由CSS伪元素生成。

面包屑导航需要什么 HTML 结构
面包屑不是靠 CSS 画出来的装饰,它本质是语义化的导航路径,必须用 <nav> 包裹,内部用 <ol>(有序列表)表达层级顺序,每个路径项用 <li>,当前页用 <li aria-current="page"> 标明。跳过这步直接写 <div> 堆文字,屏幕阅读器会读成一串无结构的词,SEO 也基本失效。
常见错误:用 <ul> 替代 <ol> —— 面包屑有明确先后,<ol> 才传达“第1级 → 第2级 → 当前页”这个逻辑;用 <span> 套链接,漏掉 <li>,导致列表项语义断裂。
-
<nav aria-label="Breadcrumb">是必须的,aria-label让辅助技术知道这是导航路径 - 每级链接必须是
<a href="...">,只有当前页用<span>或纯文本(不能带href) - 分隔符(如
/或>)建议用 CSS 的::after生成,而不是硬写在 HTML 里,避免被读屏软件重复朗读
用纯 CSS 实现分隔符和基础样式
分隔符写死在 HTML 里(比如 <li>首页</li><li>/</li><li>分类</li>)会导致语音朗读变成“首页 斜杠 分类”,干扰理解。正确做法是让 CSS 控制视觉分隔,同时保持语义干净。
关键样式点:
立即学习“前端免费学习笔记(深入)”;
- 给
nav ol设list-style: none和padding: 0; margin: 0清除默认列表样式 - 给
nav li:not(:last-child)::after添加内容:content: "/"; padding: 0 0.5em; - 当前页项(
[aria-current="page"])建议加font-weight: bold或颜色区分,但不要移除其<li>容器——否则破坏列表结构 - 避免用
float或inline-block布局,改用display: flex+gap更可控,兼容性够用(Chrome 80+/Firefox 63+)
怎么动态生成面包屑(服务端 or 客户端)
零起点不等于手写每一页的 HTML。真实项目里,面包屑几乎总是动态生成的,区别在于时机:
- 服务端渲染(如 PHP、Node.js 模板):在模板中传入一个路径数组,比如
["/","/news","/news/tech"],循环输出<li><a href="...">文本</a></li>,最后一项单独处理为<li aria-current="page">技术动态</li> - 客户端 JS(如 React/Vue):注意别在
useEffect或mounted里才渲染——首屏时 HTML 为空,对 SEO 和初始可访问性不利。应服务端先吐出静态骨架,JS 再增强 - 纯静态站点(如 Hugo/Jekyll):利用模板引擎的页面变量(如
{{ page.url }})解析路径段,自动生成对应层级文本,比手写安全得多
容易踩的坑:路径解析没处理 URL 编码(如空格变成 %20),导致面包屑显示 my%20article;或把查询参数(?id=123)也塞进路径,造成冗余层级。
响应式断点与移动端适配要点
小屏上堆满整条面包屑会挤占正文空间,但直接隐藏又损失导航信息。折中方案是截断中间项,只保留首尾 + 当前页,例如 首页 / … / 当前文章。
- 用 CSS
@media控制li:nth-child(n+2):not(:last-child)的display: none,配合::before插入省略号 - 千万别用 JS 动态计算宽度再删 DOM 节点——影响首屏渲染,且屏幕阅读器可能读到“首页 省略号 当前文章”却不知道省略了什么
- 触摸设备需确保点击区域 ≥ 44×44px,给
a加padding而非只调font-size - 如果站点有深层嵌套(如四级以上),考虑在移动端改用下拉式导航替代横向面包屑,HTML 结构要提前预留
<select>或<details>备选
最常被忽略的是:面包屑里的链接必须真实可访问。测试时随手点开任意一级,确认能返回上层目录页——很多“生成式”面包屑只拼 URL 却没校验对应页面是否存在,结果点进去 404。



















