base标签使href="#section2"被解析为/app/#section2,触发整页重载或SPA路由失效;必须用event.preventDefault()拦截或改用scrollIntoView(),且href值须为绝对URL或根相对路径(如"/app/"),否则静默失效导致404。

base 标签会让 href="#section" 变成无效跳转
浏览器把 href="#section2" 当作相对 URL 处理,一旦页面中有 <base href="/app/">,它就会拼出 /app/#section2。这个路径本身合法,但会触发整页重载或 SPA 路由不响应——因为当前 URL 是 /app/page,跳转后变成 /app/#section2,路径变更触发 history pushState 或服务端 fallback,Network 面板能看到一次对 /app/ 的空请求(状态 200,返回完整 HTML)。
原生锚点跳转的默认行为在有 <base> 时不可靠,必须主动拦截:
-
href="javascript:void(0)"彻底切断跳转,但丧失语义和可访问性,仅适合纯交互按钮 -
href="#section2"+event.preventDefault()更推荐:保留语义、支持键盘导航、能用 JS 精确控制滚动位置 - Vue/React 中不要依赖
<a href="#xxx">触发逻辑,改用@click或onClick显式调用window.scrollTo()
base href 写错就静默失效,连错误提示都没有
<base href="assets/">、<base href="../static/">、<base href="subapp/"> 全部无效。浏览器只接受以 http://、https://、// 或 / 开头的 href 值;只要不符合,整条 <base> 就被丢弃,控制台不报错、不警告,所有 <img src="logo.png"> 退回到按当前页面 URL 解析,上线后批量 404。
真正合法的写法只有两种:
立即学习“前端免费学习笔记(深入)”;
-
<base href="/myapp/">:根相对路径,开头必须是/,结尾必须带/;否则 Firefox/Opera 会截断路径(如css/app.css变成/myappcss/app.css) -
<base href="https://cdn.example.com/v3/">:绝对 URL,协议、域名、路径全明确,推荐用于 CDN 场景
base 会影响 fetch/import 的运行时路径,但很多人不知道
<base href="/subapp/"> 不仅影响 <img src="icon.png">,还会让 fetch("./api/user") 实际请求 https://example.com/subapp/api/user——而你的 API 很可能部署在根路径或独立域名下。这个行为在 Chrome/Firefox/Safari 中一致,且无法被 CORS 或服务端重定向绕过。
CSS 中 background: url(avatar.jpg) 同样受此影响(现代浏览器处理存在兼容差异),XMLHttpRequest.open("GET", "data.json") 和 new Image().src = "icon.png" 也走同一套解析逻辑。
关键点在于:fetch()、import()、new Worker() 等运行时构造的相对 URL,默认以 document.baseURI 为基准解析,而非当前 JS 文件位置。
和 Vue Router / Webpack 等配置混用,容易产生双斜杠 404
Vite 的 build.base 或 Webpack 的 publicPath 会在打包时重写静态资源路径(如 js/app.js → /admin/js/app.js)。如果此时 HTML 还手动写了 <base href="/admin/">,浏览器二次解析时会把已带前缀的路径再拼一次:/admin//admin/js/app.js——中间两个 // 导致服务端 404。
更麻烦的是,<base href="/admin/"> 和 Vue Router 的 base: '/admin/' 必须完全一致(包括结尾斜杠),差一个字符都会白屏;SSR 场景下,服务端渲染的 HTML 若没同步注入 <base>,首屏资源路径和客户端 hydration 就会不一致。
真正难的不是写对某一处,而是构建产物、CDN 缓存、Service Worker 预缓存路径全部依赖这个前缀的一致性——漏掉一个环节,资源加载就中断。



















