BEM结构中面包屑必须以breadcrumb为唯一块,因li和a是HTML原生语义标签,无命名空间易被全局样式污染,破坏块自包含原则,导致状态控制、可访问性及样式解耦失效。

面包屑导航的BEM结构必须以 breadcrumb 为唯一块(block),所有子元素严格限定在 breadcrumb__list、breadcrumb__item、breadcrumb__link、breadcrumb__text、breadcrumb__separator 范围内,不能用 li 或 a 自行承担语义与样式双重责任。
为什么不能把 li 和 a 当作 BEM 元素来用
常见错误是写成 <ol class="breadcrumb"><li><a href="#">首页</a></li></ol>,然后给 li 加样式或 JS 行为。这破坏了 BEM 的“块自包含”原则:li 是 HTML 语义标签,不是你定义的块的一部分;它没有命名空间,容易被全局样式污染,也导致折叠、禁用、可访问性逻辑难以统一控制。
- 当前页状态必须靠
breadcrumb__item--current这类修饰符表达,而不是删掉a或加disabled属性 - 分隔符必须用
breadcrumb__item:not(:last-child)::after实现,而非硬塞<span class="breadcrumb__separator">/</span>—— 否则屏幕阅读器会读出多余字符 - 如果用 Vue/React 渲染列表,
v-for或.map()必须输出带完整 BEM 类名的<li class="breadcrumb__item">,不能只套一层 wrapper
breadcrumb__separator 的实现必须避开伪元素陷阱
很多人用 breadcrumb__item::after 加内容,结果最后一条也显示分隔符。正确做法是限定作用范围:
- 必须用
breadcrumb__item:not(:last-child)::after,且确保:not(:last-child)能准确匹配——这意味着breadcrumb__item必须是breadcrumb__list的直接子元素,中间不能插<div class="wrapper">或 Fragment - 伪元素内容建议用
content: "›"或 SVG,避免空格缩进导致热区偏移 - 若需支持 RTL(如阿拉伯语),应配合
direction: rtl+transform: scaleX(-1),而不是换字符
折叠场景下如何用修饰符控制 breadcrumb__item
后台系统常需要折叠中间项(如 “首页 / … / 用户管理 / 权限设置”),此时不能删 DOM 或改结构,而是靠修饰符驱动样式和可访问性:
立即学习“前端免费学习笔记(深入)”;
- 用
breadcrumb__item--collapsed标记被折叠项,CSS 中隐藏其breadcrumb__text并显式设aria-hidden="true" - 折叠项的
breadcrumb__link应保留href和键盘焦点能力,仅视觉隐藏,否则破坏可访问性 - 不要用
display: none隐藏整个breadcrumb__item,会导致屏幕阅读器跳过上下文,应只隐藏文本内容 - JS 控制折叠时,优先切换类名而非操作 DOM,确保 SSR 和 hydration 一致
真正难的不是写对类名,而是守住“breadcrumb 是一个块”的边界意识:一旦开始在内部混用原生标签语义、手动插入分隔符、或让 JS 直接操作 li,BEM 就退化成了带下划线的普通命名,后续任何状态扩展(比如暗色模式、国际化分隔符、键盘导航焦点链)都会变成补丁堆叠。


















