应优先服务端/构建时注入高亮,客户端用 pathname 标准化解析+前缀匹配;SPA 需监听路由;aria-current="page" 必须配 CSS 且不与 class 冗余;SSG 要静态标注避免闪烁。

怎么让导航菜单自动高亮当前页面
靠 CSS 类名手动加 active 不可靠,容易漏改、难维护。真正稳的方式是服务端或构建时注入,或者用 JavaScript 在客户端比对 window.location.pathname 和链接 href 后缀是否匹配。
常见错误是只比对完整 URL,结果 /blog 匹配不了 /blog/ 或 /blog/post-1;也有人用 indexOf 粗暴包含,导致 /user 错误高亮 /users。
- 推荐用
new URL(link.href, window.location.origin).pathname标准化解析路径,再做前缀匹配(注意结尾加/避免子路径误伤) - 单页应用(SPA)必须监听路由变化,比如 Vue Router 的
router.afterEach或 React Router 的useLocation+useEffect - 服务端渲染(如 Next.js、Nuxt)优先在组件 props 里传入
isActive,避免客户端闪动
aria-current="page" 是不是加了就完事了
不是。它只是语义标注,不带样式,也不影响焦点或键盘行为。很多开发者加了但没配 CSS,屏幕阅读器能读出“当前页面”,视觉用户却完全看不出区别。
更麻烦的是,aria-current 值必须是合法枚举:"page"、"step"、"location" 等,写成 "true" 或 "active" 属于无效属性,AT(辅助技术)直接忽略。
- 必须配合 CSS:比如
[aria-current="page"] { font-weight: bold; },否则等于没标 - 不要和
class="active"冗余共存,除非样式逻辑不同(例如:视觉用 class,无障碍用 aria-current) - 多级导航中,只给最具体那一项加
aria-current="page",不是整条路径都加
为什么用 pathname 而不用 hash 或 search 判断当前项
因为导航项通常对应路由的路径段(path),不是锚点或参数。用 window.location.hash 只能处理 #section1 这类页面内跳转;用 search 更离谱——?sort=desc 显然不该影响“首页”是否高亮。
典型翻车场景:URL 是 /products?id=123,结果你拿整个 search 去比对导航链接,一比就错;或者用了 hash,但项目根本没用锚点导航,导致永远不匹配。
- 只依赖
pathname,它代表资源位置,和导航意图一致 - 如果后端路由带查询参数(如
/admin?tab=users),应提取tab值单独判断,而不是把整个 URL 当路径用 - 注意 trailing slash:Nginx 或 Vercel 默认可能重写
/about→/about/,比对前统一处理掉末尾斜杠
静态站点生成器(SSG)里怎么避免 JS 闪烁
像 Hugo、Jekyll、Astro 这类工具,在构建时就知道当前页面路径,完全没必要等 JS 执行后再高亮——那样会先显示无样式菜单,再突然变色,对 SEO 和用户体验都不好。
核心原则:能静态决定的,绝不推到客户端。JS 只兜底处理动态内容或 SPA 场景。
- Hugo 中用
{{ if eq .Page.RelPermalink $link.url }}直接输出aria-current="page" - Astro 用
{current ? 'aria-current="page"' : ''}在服务端计算布尔值 - Jekyll 可用
{% if page.url == link.url %}aria-current="page"{% endif %}
真正容易被忽略的是:很多人写了客户端高亮逻辑,却忘了在 SSG 模板里也同步加静态标注。结果代码跑两遍,CSS 冲突,甚至 aria-current 被覆盖两次。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











