必须用 <nav> 因其是 HTML5 明确规定的语义化导航标签,浏览器、搜索引擎和读屏器依赖该标签识别导航区域;若用 <div class="nav">,将导致 Tab 顺序错乱、SEO 权重下降、屏幕阅读器忽略该区域,严重损害可访问性与可用性。

必须用 <nav>,不是“可以不用”;当前页高亮必须靠 JS 判断路径,硬编码 class="active" 会崩。
为什么非得用 <nav> 而不是 <div class="nav">
浏览器、搜索引擎、读屏器靠标签语义识别“这是导航”,<nav> 是 HTML5 明确规定的功能标签,不是视觉装饰。写成 <div class="nav"> 看起来一样,但实际后果包括:
- 键盘 Tab 顺序可能错乱(辅助技术无法跳过或定位该区域)
- SEO 权重下降(爬虫不认为这是导航链接集合)
- 屏幕阅读器直接忽略整个区域,用户听不到“主导航”提示
常见错误:把搜索框、登录按钮塞进同一个 <nav>——它们属于 <search> 或 <form>,语义混杂会导致播报混乱;一个页面堆 5 个 <nav>——建议控制在 2–3 个(主导航 + 页脚链接组 + 面包屑),再多就该用 aria-label 显式区分。
<ul><li><a> 是语义最优结构,别用 <div><a> 拼凑
菜单本质是“一组并列的导航项”,<ul> 天然表达这种无序集合关系,比 <div> 更准确。浏览器默认对 <li> 做合理排列,CSS 控制也更干净:
立即学习“前端免费学习笔记(深入)”;
- 清除
list-style-type和padding/margin即可归零起点,无需额外重置 -
<li>是天然的点击区域容器,display: block在<a>上就能撑满,点击热区更大 - 嵌套下拉菜单时,
<ul><li><ul>层级清晰,ARIA 属性(如aria-haspopup)更容易绑定
用 <div><a> 虽然自由,但等于放弃语义和可访问性基础,后期加键盘导航、焦点管理、屏幕阅读支持成本翻倍。
当前页高亮不能靠服务端硬写 class="active"
HTML 本身无法感知 URL 路径变化,所有“静态写死 active”的方案都会在以下场景失效:
- 路径末尾带斜杠(
/aboutvs/about/) - 哈希路由(
#!/projects)或 History API 动态更新 - 本地开发用
file://协议时window.location.origin为空
前端简单判断逻辑(建议放 </body> 前):
document.querySelectorAll('nav a').forEach(link => {
const currentPath = window.location.pathname || '/';
const linkPath = new URL(link.href).pathname;
// 兼容 file:// 协议
const isMatch = linkPath === currentPath || link.href.startsWith(currentPath);
if (isMatch) link.classList.add('active');
});
注意:这个逻辑只匹配 pathname,不处理 query 或 hash;如需更细粒度(比如高亮“产品”下所有子页面),得改用正则或前缀匹配。
Flexbox 布局比 float / inline-block 更稳,但别忘了 wrap
横向导航栏首选 display: flex,现代浏览器全覆盖(IE11 除外)。关键点:
- 用
gap控制项间距,比每个<li>加margin-right干净,也避免“最后一个要不要清 margin”的纠结 -
justify-content: space-around比space-between更适合文字长度不均的导航项,两端留白更均衡 - 千万别在
<nav>上设white-space: nowrap——小屏会强制横向滚动,破坏体验;改用flex-wrap: wrap+ 媒体查询自然折行
IE11 兼容需退回到 margin-right,并手动处理最后一个子项样式(比如用 :last-child { margin-right: 0; })。
最常被忽略的是面包屑没加 aria-label="当前位置"——即使用了 <nav>,不标注意图,读屏器仍可能读成“导航”而非“您当前所在位置”。语义标签只是起点,ARIA 注解才是让意图真正传达出去的最后一环。



















