Base Element and Relative URLs
How <base href> rewrites relative URLs for links, scripts, and forms — powerful for static hosts, dangerous when set accidentally.
- html
- base
- urls
The <base> element sets a default URL and target for relative URLs in the document. One tag in <head> changes how every relative href, src, and form action resolves. That can fix asset paths on static hosts — or silently break navigation in SPAs.
Docs: MDN <base>, URL resolution.
Syntax
<head>
<base href="https://cdn.example.com/app/" />
<!-- optional default target for links -->
<!-- <base target="_blank" /> -->
</head>
Rules:
- At most one
<base>with anhrefshould be used; first wins in practice per spec nuances — don’t stack them. - Must live in
<head>. hrefshould typically end with/when it represents a directory.
Resolution examples
<base href="https://example.com/docs/" />
<a href="guide.html">Guide</a>
<!-- → https://example.com/docs/guide.html -->
<img src="/logo.svg" alt="" />
<!-- root-relative: still https://example.com/logo.svg — leading / is path-absolute -->
<img src="images/a.png" alt="" />
<!-- → https://example.com/docs/images/a.png -->
<a href="https://other.test/x">External</a>
<!-- absolute URLs ignore base -->
Root-relative paths (/foo) resolve against the origin, not the base path. Document-relative paths (foo, ./foo, ../foo) use the base URL.
Forms and scripts
<base href="https://api.example.com/v1/" />
<form action="submit">…</form>
<!-- posts to https://api.example.com/v1/submit -->
<script src="app.js"></script>
<!-- loads https://api.example.com/v1/app.js — often not what you want -->
A base aimed at a CDN can break same-origin API relative calls if you’re not careful. Prefer absolute paths or explicit absolute URLs for APIs.
SPA and router footguns
Client routers that use relative links assume the document URL. With <base href="/app/">:
<a href="settings">Settings</a>
<!-- resolves under /app/ -->
But some bundlers inject scripts with relative paths that depend on base — Vite/Webpack expose base config for this reason. Mismatch between build base and HTML <base> causes blank pages.
When to use it
| Scenario | Verdict |
|---|---|
Static site hosted in a subpath /blog/ |
Often yes — align with build base |
| Marketing site at domain root | Usually unnecessary |
| Third-party HTML email | Different rules; often avoid |
| Temporary debug hack in production | No |
Alternatives
- Configure bundler
base/publicPath - Use root-relative asset URLs
<link rel="…">absolute CDN URLs for vendors
Interview out-loud
“<base href> sets the resolution base for relative URLs in the document. Root-relative paths still use the origin root. It’s useful for apps deployed under a subpath, but a wrong base breaks scripts, forms, and links. I keep a single base in head and align it with the bundler’s public path.”
Footguns
- Forgetting the trailing slash on directory bases.
- Base pointing at a CDN while forms should post to the app origin.
targeton base forcing every link to new tabs.- Multiple base tags from concatenating layouts.
- In-page
#hashlinks behaving oddly with certain base combinations — test.
Bundler alignment example
Vite base: '/docs/' should match:
<base href="/docs/" />
or rely on absolute root paths generated by the bundler without a HTML base tag. Pick one strategy. Mixed relative CSS url(./img.png) plus an unexpected <base> is a classic “works on homepage only” bug when routes deepen (/docs/a/b/).
Related
Further reading
Related guides
- Accessibility Tree OverviewHow browsers build the accessibility tree from DOM and CSS — roles, names, states, what’s pruned, and how to inspect it in DevTools.
- Audio and Video ElementsNative audio/video — controls, sources, captions, autoplay policies, and accessibility requirements for media on the web.
- Autocomplete and Name Attributesname and autocomplete on form fields — password managers, autofill tokens, and why missing names break real users more than demos.
- contenteditable Basicscontenteditable surfaces — what the browser gives you, sanitization, keyboard and a11y gaps, and when to pick a real editor library.
- data Attributesdata-* attributes for embedding element metadata — dataset API, CSS hooks, validation limits, and when not to store app state in the DOM.