合规面包屑必须用包裹且使用,各级为可跳转,末项加aria-current="page",分隔符用css实现。

面包屑必须用 <nav></nav> 包裹,且带 aria-label="breadcrumb"
纯视觉的“首页 > 产品 > 详情”写法没有语义,对屏幕阅读器不可见,也不被搜索引擎识别为导航路径。真正合规的面包屑需同时满足两个硬性条件:外层是 <nav></nav> 元素,且必须声明 aria-label="breadcrumb"(不能只写 role="navigation",也不能用 class 或 id 替代)。否则辅助技术会把它当成普通文本或忽略。
-
<ol></ol>比<ul></ul>更合适:层级有明确先后顺序,<ol></ol>天然表达“路径深度”,部分读屏器会播报序号(如“第1项,首页”),增强上下文感知 - 每级必须是真实可跳转的
<a></a>,末项用<a aria-current="page"></a>标记,不能是纯文本或<span></span> - 避免用
<div> + CSS Flex 模拟列表结构——它绕过了语义树,爬虫和读屏器都看不到路径关系 <h3>为什么不用 <code><section></section>或<aside></aside>套面包屑<section></section>表示内容逻辑分块,比如“评论区”“相关推荐”,不是导航;<aside></aside>是附属信息容器,典型场景是术语解释、作者简介——删掉它主内容依然完整。而面包屑本质是用户可操作的导航入口集合,属于页面级导航体系的一部分,和主导航、页脚导航同属一类,所以必须归入<nav></nav>。- 若页面含多个
<nav></nav>(如顶部主导航 + 面包屑 + 页脚链接),必须用aria-label明确区分,例如:<nav aria-label="主导航"></nav>、<nav aria-label="breadcrumb"></nav>、<nav aria-label="页脚导航"></nav> - 不要用
aria-labelledby或id引用外部标题——面包屑本身没有可见标题,aria-label是唯一可靠方式
<ol></ol>内部结构要点:链接、当前页、分隔符<ol></ol>的每个<li>应只包含一个<a></a>(或末项为<a aria-current="page"></a>),不要嵌套<span></span>或额外标签干扰语义流。- 当前页链接仍要保留
href属性(可指向自身 URL),仅靠aria-current="page"不足以维持语义完整性 - 分隔符(如
/或>)必须用 CSS::after实现,不能写死在 HTML 里,否则会被读屏器朗读为“斜杠”“大于号”,干扰路径理解 - 示例片段:
<nav aria-label="breadcrumb"><ol> <li><a href="/">首页</a></li> <li><a href="/products">产品</a></li> <li><a href="/products/editor" aria-current="page">编辑器</a></li> </ol></nav>
前端框架里别从
useRoute().path动态解析面包屑直接对 URL 字符串做正则拆分(如
path.split('/').filter(Boolean))在真实项目中极易出错:- 路由参数如
/post/:id会被误渲染成“post :id”,而非“文章详情” - 同一路径不同语义(如
/settings在个人页 vs 团队页)无法区分 - 国际化时路径不变但文字要变,硬解析无法适配
- 带查询参数的路径(如
/docs?version=latest)拆分会生成无效链接
正确做法是在路由定义中显式声明
meta: { breadcrumb: '用户设置' },组件内遍历useRoute().matched提取所有匹配项的meta.breadcrumb拼接。这确保了面包屑基于业务语义,而非运行时路径字符串。容易被忽略的一点:面包屑层级必须与用户认知路径一致,而不是服务器目录结构。比如后台 API 文档页显示
/v2/api/docs这种路径,应该用<code>块单独展示,另建一套基于功能的面包屑(如“开发者中心 > API 文档 > 编辑器接口”)。 - 若页面含多个











