base href写错会导致所有相对资源404且浏览器静默忽略:仅以http://、https://、//或/开头且结尾带/的绝对URL或根相对路径才生效;必须置于<head>最前且唯一;不影响fetch、import等运行时路径。

base href 写错会导致 <script src="app.js"> 404</script>
<base> 标签只在 HTML 解析阶段生效,且仅改写“纯相对路径”——也就是不以 /、: 或协议开头的路径。一旦你写了 <base href="js/"> 或 <base href="../static/">,浏览器会直接忽略整行,不报错也不警告。结果就是 <script src="app.js"> 仍按当前页面 URL 拼接,比如在 https://example.com/a/b/page.html 下,它会尝试加载 https://example.com/a/b/app.js,而非你预期的 https://example.com/a/b/js/app.js。
-
<base href="js/">❌ 静默失效(不是绝对 URL,也不是根相对路径) -
<base href="/myapp/">✅ 有效(根相对路径,结尾必须带/) -
<base href="https://cdn.example.com/v4/">✅ 有效(绝对 URL,推荐 CDN 场景) -
<base href="/myapp">⚠️ Firefox 可能截断为/myappcss/(结尾缺/)
script src 是受 base 影响的,但 import() 和动态 import 不是
静态 <script src="utils.js"> 的路径解析发生在 HTML 解析时,所以它严格遵循 <base> 设置。但 JS 运行时行为完全绕过 <base>:
-
import('./router.js')→ 按当前 JS 文件所在路径解析,与<base>无关 -
fetch('./api/data.json')→ 按当前页面 URL 解析,不受<base>影响 -
document.createElement('script').src = 'legacy.js'→ 动态创建的 script 元素,路径也绕过<base>
这意味着:你不能靠 <base> 统一管理所有脚本路径,尤其在混合使用静态引入和 ES Module 动态导入的项目里。
SPA 构建中 base 和 publicPath / build.base 双重配置易冲突
Webpack 的 publicPath 和 Vite 的 build.base 已在构建阶段重写了所有静态资源引用路径。如果你再手动加 <base href="/subapp/">,就可能造成路径叠加:
立即学习“前端免费学习笔记(深入)”;
- Vite 设了
build.base: '/subapp/',输出<script src="/subapp/assets/index.abc123.js"> - 又手写
<base href="/subapp/">→ 浏览器把src="/subapp/assets/..."当作根路径,没问题 - 但如果误写成
<base href="/subapp">(缺结尾/),Firefox 可能拼出/subappassets/...,404 - 更危险的是:Webpack
publicPath: '/subapp/'+ 手动<base href="/subapp/">→ 某些 loader 可能二次拼接,导致/subapp//subapp/js/app.js
结论:现代构建工具场景下,优先用 build.base 或 publicPath,HTML 中一般不该再手动写 <base>。
base 必须放在 <head> 最前面,否则对前面的 script 无效
<base> 的作用是“从它出现的位置开始,影响后续所有纯相对路径”。如果它出现在 <link rel="stylesheet"> 之后,那么那个 CSS 文件的路径已经按原始页面 URL 解析完毕,<base> 对它毫无作用。
-
<head><base href="/app/"><script src="init.js"></script></head>→init.js走/app/init.js -
<head><script src="polyfill.js"></script><base href="/app/"><script src="main.js"></script></head>→polyfill.js不受影响,main.js才走/app/main.js -
<body><base href="/app/"></body>→ 整个<base>被浏览器忽略
最容易被忽略的一点:它不作用于已解析完成的节点,只对后续解析生效;而且没有 fallback 机制,写错或放错,就是静默失败。



















