最稳的起点是手动为当前页导航链接添加 class="nav-link active",需每页单独写死,避免复制粘贴导致高亮错位;推荐搭配 aria-current="page" 提升可访问性,并用 body 类+属性选择器或 JS 路径匹配实现自动化,但须注意路径标准化与选择器优先级。

手动加 class="active" 是最稳的起点
纯静态 HTML 网站里,浏览器不会自动识别当前页——class="active" 必须每个页面单独写死在对应链接上。比如 about.html 中,只有 About 那个 <a></a> 标签带 class="nav-link active",其他链接不能有。
常见错误现象:所有页面都复制同一份导航 HTML,结果每个页面的“首页”都高亮;或漏改某页,导致 About 页面里“Contact”还亮着。
实操建议:
- 保持语义清晰,别只写
class="active",用class="nav-link active"这类组合类名 - CSS 规则写成
.nav-link.active,优先级比.nav-link高,避免被覆盖 - 如果样式不生效,先检查是否被
a:hover或更具体的选择器压住了,临时加!important可验证,但长期应优化选择器
aria-current="page" 比 class 更规范但需配 CSS
aria-current="page" 是 WAI-ARIA 官方标准,屏幕阅读器能识别,但它本身不触发样式——必须配合属性选择器才能高亮。
立即学习“前端免费学习笔记(深入)”;
正确写法是:<a href="/about" aria-current="page">About</a>,再写 CSS:a[aria-current="page"] { background-color: #007bff; color: white; }。
容易踩的坑:
- 不能只写
a[aria-current],必须带值匹配"page",否则会误中aria-current="step"等其它类型 - 别和
class="active"同时加在一个链接上,除非你真需要 JS 和语义双控,否则冗余且易维护错 - 服务端渲染或静态生成工具(如 Jekyll、Hugo)可自动注入这个属性,但纯手写 HTML 仍得逐页检查
用 window.location.pathname 做前缀匹配要防路径陷阱
JS 自动高亮看似省事,但 window.location.pathname 直接比对很容易翻车。比如当前是 /blog/post1,你想高亮 /blog 这个导航项,就不能用 === 全等,得用 startsWith()。
关键点在于标准化解析 href:
- 用
new URL(link.href, window.location.origin).pathname提取 href 的真实路径,避免相对路径或协议差异(如./about或//example.com/contact) - 匹配前先剥离查询参数和哈希,因为
pathname本身不含?ref=home或#top - 结尾加
/判断:匹配/about/时,要防止/about-us被误中,可用path.startsWith(match + '/') || path === match - 子目录部署(如项目跑在
/my-app/下)时,得先从pathname中剔除 base path,否则所有匹配都失败
body 类 + 属性选择器是折中方案
不想手改每个页面,又不愿写 JS?给每个页面的 加唯一 class 是个实用折中法。比如 about.html 写 ,contact.html 写 。
CSS 就写成:body.page-about nav a[href="/about"], body.page-contact nav a[href="/contact"] { color: #007bff; }。
这个方式的限制很实在:
- 每个页面的
class 必须唯一且稳定,不能靠 JS 动态写,否则首屏无样式 - 导航链接的
href必须是绝对路径(如/about),不能是相对路径(如./about),否则 CSS 选择器无法精确命中 - 一旦导航结构变化(比如新增 /projects),就得同步补 CSS 规则,页面多时维护成本会上升
真正难的不是选哪种方式,而是统一路径格式、处理好子目录部署、以及确保 CSS 选择器足够具体又不过度耦合。静态站点手动维护最可控,动态场景下 JS 匹配逻辑必须做足边界判断——URL 解析那一步,错一点,整个高亮就失效。



















