必须用<nav>包裹导航条且链接为<a>,因其提供语义信号,保障SEO、键盘导航与读屏支持;错误使用<div class="nav">或滥用<nav>会破坏可用性;Flex布局优于float/inline-block;高亮需JS动态判断路径;移动端汉堡菜单须配全ARIA属性。

不用 JavaScript 也能做出能点、能高亮、不闪退的导航条,但必须用 <nav> 包裹,且链接得是 <a> —— 否则浏览器根本不认它是可交互区域,点击没反应、悬停无效、高亮失效全由此起。
为什么必须用 <nav> 而不是 <div class="nav">
它不是视觉装饰,而是语义信号:告诉浏览器、搜索引擎和读屏软件“这是主导航区”。不用它,SEO 权重下降,键盘 Tab 焦点顺序错乱,视障用户无法用快捷键跳转到导航,等于主动放弃可用性底线。
常见错误现象:
-
<div class="nav"><a>首页</a><a>关于</a></div>—— 读屏器播报“一段文字”,不是“导航区域” - 同一页面塞了 4 个
<nav>,包含搜索框、登录按钮、广告位 —— 语义混杂,辅助工具直接忽略或报错
正确做法:
立即学习“前端免费学习笔记(深入)”;
- 一个页面最多 2–3 个
<nav>:顶部主菜单、页脚快捷链接、面包屑(后者需加aria-label="当前位置") - 子菜单用
<ul>,别嵌套<nav>;纯锚点跳转区用<section>更合适
display: flex 是现代导航布局的默认起点
老式 float: left 或 display: inline-block 在响应式场景下极易崩:父容器塌陷、换行间隙不可控、小屏溢出、垂直对齐偏移。Flex 布局天然规避这些,且 IE11+ 已全覆盖。
关键实操点:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 给
<nav>的直接子容器(如<ul>)设display: flex,不是给<nav>自身 - 用
gap: 1.5rem控制项间距,比margin-right干净得多;IE11 不支持gap时,退回到margin-right并手动清除最后一项 - 避免在
<nav>上设white-space: nowrap—— 小屏会强制横向滚动,改用flex-wrap: wrap+@media自然折行
居中推荐 justify-content: center 或 space-around(文字长度不均时更均衡),别依赖 text-align: center + inline-block。
当前页高亮必须靠 JS 动态判断路径
HTML 本身无法感知“我在哪一页”,硬编码 class="active" 到所有页面里是维护噩梦:路径微调(/about vs /about/)、哈希路由(#!/projects)、本地开发(file:// 协议)都会导致匹配失败。
简单可靠的前端判断逻辑(放 </body> 前):
document.querySelectorAll('nav a').forEach(link => {
const currentPath = window.location.pathname || '/';
const linkPath = new URL(link.href).pathname;
if (linkPath === currentPath) {
link.classList.add('active');
}
});
注意点:
- 本地文件协议下
window.location.origin为空,需额外判断link.href.startsWith(currentPath) - 若用 Vue Router / React Router 等前端框架,必须监听路由变化事件,不能只在页面加载时执行一次
- 服务端渲染项目,优先由后端注入
class="active",更稳定、首屏无闪烁
移动端汉堡菜单的 ARIA 属性不能漏
纯靠 CSS display: none 切换菜单面板,视障用户完全不知道按钮和面板的关系,也无法用键盘触发。Safari + VoiceOver 支持 aria-controls,但旧版 Android TalkBack 可能忽略,所以必须配合 aria-hidden 和 inert。
最小必要结构:
- 汉堡按钮:
<button aria-expanded="false" aria-controls="mobile-menu">☰</button> - 菜单面板:
<ul id="mobile-menu" aria-hidden="true"></ul> - 展开时同步更新:
button.setAttribute('aria-expanded', 'true')+menu.setAttribute('aria-hidden', 'false')+menu.removeAttribute('inert')
别只写 aria-expanded 就完事 —— 缺少 aria-controls,屏幕阅读器根本不会把按钮和面板关联起来,用户点完只会说“没反应”。


















