最稳妥结构是用包裹,每项为,当前页用aria-current="page"标识且不加链接;分隔符用li:not(:last-child)::before{content:">"}实现,确保语义清晰、可访问性强、css可控。

面包屑导航的 HTML 结构怎么组织才利于 CSS 控制
直接用 <nav></nav> 包裹 <ol></ol> 是最稳妥的选择,语义清晰且天然支持层级表达。避免用 <div> 堆砌或依赖 JS 动态生成结构——CSS 的 <code>::before 和 content 无法操作 DOM 节点,只能修饰已有元素。
推荐结构:
<nav aria-label="Breadcrumb"><ol>
<li><a href="/home">Home</a></li>
<li><a href="/products">Products</a></li>
<li aria-current="page">Wireless Headphones</li>
</ol></nav>
-
aria-label和aria-current="page"是可访问性刚需,不能省 - 最后一项不用
<a></a>,否则屏幕阅读器会误判为可跳转链接 - 不要给
<li>加类名(如breadcrumb-item),纯靠:not(:last-child)或:nth-child(n+2)选中分隔符更干净
用 ::before 和 content 插入分隔符的正确写法
核心是:只对非末尾的 <li> 添加分隔符,且必须用 ::before(不是 ::after),否则符号会出现在文字右侧空白处,破坏对齐。
CSS 示例:
nav ol {
display: flex;
list-style: none;
padding: 0;
margin: 0;
}
nav ol li {
margin-right: 0.5rem;
}
nav ol li:not(:last-child)::before {
content: ">";
margin-right: 0.5rem;
color: #666;
}
-
content: ">"是最简方案;若需图标,可用content: "›"(HTML 实体)或content: url(arrow.svg) - 绝对不要写
content: " > "(带空格),会导致首尾多出不可控空白 - 如果用 Flex 布局,
margin-right加在<li>上比加在::before上更易控制整体间距
为什么 content 无法动态插入路径文本
content 属性不支持 JS 变量、属性值绑定或 DOM 文本提取,它只接受字符串字面量、attr() 函数或 URL。所以你不能用它“自动读取 <a></a> 的 href 并转成文字”。常见误解是以为 content: attr(href) 能显示路径,但它实际插入的是 /products 这种原始值,而非用户友好的 “Products”。
-
attr(href)只能取属性值,不能做任何转换(大小写、截断、i18n) - 若真需要动态文本,必须由 HTML 提供(服务端渲染或前端模板注入),CSS 只负责装饰
- 想用图标替代文字?可以,但得提前在 HTML 里写好
<li aria-label="Products"><svg>...</svg></li>,再用content: ""配合visibility: hidden隐藏文字
响应式断点下隐藏中间项的兼容写法
当屏幕变窄时,常见做法是只保留首项 + 末项,中间用 … 替代。这不能靠 content 动态计算,得用 CSS 选择器显式控制可见性。
@media (max-width: 480px) {
nav ol li:not(:first-child):not(:last-child) {
display: none;
}
nav ol li:first-child::after {
content: "...";
margin-left: 0.5rem;
color: #999;
}
}
- 用
display: none而不是visibility: hidden,避免占位干扰 Flex 布局 -
::after加在首项后,比单独加一个<li>…</li>更轻量,且无需 JS 操控 DOM - 注意:IE11 不支持
:not(:first-child):not(:last-child)的多重否定,如需兼容,改用:nth-child(n+2):not(:last-child)
content 做语义工作——它只负责“画”,不负责“说”。











