The HTML Base Element
Imagine a letter that says "meet me at the cafΓ© on the corner". Which corner? It depends where you are standing. A web address works in the same way: a relative address such as about.html only makes sense from somewhere. By default, that somewhere is the address of the page it is written on.
The <base> element changes that starting point for the whole page. It is a tiny element with big effects, and, as you will see, with big risks. Many experienced developers avoid it. Understanding why will make you better at both URLs and security.
What You Will Learnβ
- How relative addresses are worked out
- What
<base href>does, and which things it affects - The classic trap:
#fragmentlinks stop working - What
<base target>does - The rules for using
<base> - Why it is a security risk, and how to limit that
- Safer alternatives
The Big Ideaβ
- HTML Code
- URL Resolver
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<base href="https://example.com/blog/">
<title>Base demo</title>
</head>
<body>
<a href="about.html">About</a> <!-- https://example.com/blog/about.html -->
<a href="/contact">Contact</a> <!-- https://example.com/contact -->
<a href="#top">Back to top</a> <!-- https://example.com/blog/#top (!) -->
<img src="images/logo.png" alt="Logo"> <!-- https://example.com/blog/images/logo.png -->
</body>
</html>
Switch the base element on and off, and watch each address change. Look carefully at the #top row.
Relative and Absolute Addressesβ
| Kind | Example | Meaning |
|---|---|---|
| Absolute | https://example.com/page | A complete address. Works from anywhere |
| Root-relative | /contact | Starts from the root of the same site |
| Relative | about.html, ../up.html, images/a.png | Starts from the base address |
| Fragment | #top | A place inside the base address's page |
Without a <base> element, the base address is the page's own address. With one, it is whatever href the <base> says. Every relative address on the page then starts from there.
The <base> Elementβ
<base href="https://example.com/docs/">
| Attribute | Meaning |
|---|---|
href | The new base address for relative addresses on the page |
target | The default target for links and forms, such as _blank or _self |
At least one of the two must be present.
What It Affectsβ
- Links (
<a href>) and image maps - Images, audio, video, and other media with
src - Scripts (
<script src>) and stylesheets (<link href>) - Form addresses (
<form action>) - Anything else that reads a relative address from HTML
- The value of
document.baseURIin JavaScript
What It Does Not Affectβ
- Absolute addresses. They are already complete.
- Addresses inside a CSS file, such as
url(images/bg.png). These are relative to the stylesheet's own address. @importinside a CSS file, for the same reason.- The address of the page itself, so the address bar does not change.
The Trap: Fragment Linksβ
Take a look at this ordinary link, which jumps to the top of the page:
<a href="#top">Back to top</a>
Without <base>, it means "the top of this page". With <base href="https://example.com/blog/">, the browser works out the address as https://example.com/blog/#top, and so it leaves the page and goes to a different one. The same happens with skip links (#main), tables of contents, tabs that use fragments, and SVG references that point to ids.
This is the most common reason for <base> bugs. If you must use a base element, you need to write same-page links as full addresses, or handle them with script. That is a strong reason not to use it.
<base target>β
<base target="_blank">
This sets the default target for all links and forms that do not set their own. _blank opens every link in a new tab.
- It is convenient for one small situation: a page that shows an external list, such as an embedded widget or an email preview.
- For a normal page, it is disorienting and harmful: many new tabs, and a lost back button. People using screen readers and those with cognitive disabilities find unexpected new windows especially difficult.
- Links can still override it:
<a href="β¦" target="_self">. - Browsers treat
target="_blank"links asrel="noopener"by default today, but it is still good practice to writerel="noopener"on external links yourself, as older browsers do not.
Rules for Using <base>β
- At most one
<base>element per page. If there are several, only the first withhref(and the first withtarget) counts. - It must be in the
<head>. - Put it before any element that uses an address, such as
<link>and<script>, or those earlier addresses may be worked out without it. - The
hrefcan be absolute (best) or relative. - It has no content and no closing tag.
Try the checker, which uses the browser's real parser:
- HTML Code
- Browser Output
<head>
<meta charset="utf-8">
<base href="https://example.com/app/"> <!-- first, before anything with an address -->
<link rel="stylesheet" href="css/site.css">
<script src="js/app.js" defer></script>
</head>
When Is <base> Actually Useful?β
Honestly, rarely. Reasonable cases:
- A static page served from many different places (such as an offline copy or a preview tool) where you cannot change its internal addresses, and want them all measured from one place.
- A quick prototype of a page, saved in one folder but using files from another.
- Embedded or generated HTML, such as a saved email or a rendered note, where relative addresses need a known base.
- A site hosted under a sub-folder (for example
/my-project/), where you want relative addresses to start there. Most tools solve this in a safer way (see below).
Better Alternativesβ
| Need | Better choice |
|---|---|
| Site under a sub-folder | Use root-relative addresses with the folder prefix, or the build tool's setting for its base path |
| Same addresses on every page | Use root-relative addresses (/css/site.css) |
| Links open in a new tab | Add target="_blank" rel="noopener" to those links only |
| Load assets from a CDN | Write full CDN addresses, or let your build tool add them |
In Docusaurusβ
Docusaurus does not rely on a <base> element. Instead, it has a baseUrl setting in docusaurus.config.js (for example /my-project/ when hosted on GitHub Pages), and it adds that prefix to the addresses it generates. If your site works with baseUrl set correctly, you do not need a base element, and adding one could break your links.
Good Habitsβ
- Avoid
<base>unless you have a clear reason. - If you use it, use one, early in the head, with a full address.
- Remember that
#fragmentlinks change meaning. - Do not use
target="_blank"as a site-wide default. - Prefer root-relative addresses, or your build tool's base-path setting.
- Test every kind of link (relative, root, fragment, form) after adding a base.
- Block injected base elements with a
base-urirule (see below).
Accessibility Checklistβ
- Skip links and in-page links (
#main, a table of contents) still stay on the page. - No unexpected new tabs are opened. If a link does open one, say so in the link text.
- Same-page navigation still works with the keyboard.
- Forms still submit to the right place.
- Images and media still load, so their alternative text is not the only thing left.
- Anchors used by tabs, accordions, and tables of contents still work.
Security and Privacy Notesβ
- Base tag injection is a real attack. If an attacker can add a
<base href="https://evil.example/">to your page (through a comment, a profile field, or any place that lets some markup through), then every relative link, form, and script address on the page is measured from their server. A relative<script src="js/app.js">could now load their code, and a relative form could send passwords to them. - Defend with a
base-urirule in your Content-Security-Policy, for examplebase-uri 'self'(or'none'if you never use a base element). The browser then refuses base elements that break the rule. Send the policy in a header, because a policy in a meta tag does not cover this reliably. - Escape all user-provided text, so no one can add markup to your page.
- Use absolute addresses for critical scripts and forms, so that even a hijacked base cannot redirect them.
- A base element can hide where links really go. A reader who hovers over a link sees the final address, but a developer reviewing the source may be misled. Keep it obvious.
- A base with
target="_blank"can expose your page to the pages it opens, in older browsers, ifrel="noopener"is missing.
If your site never needs <base>, add base-uri 'none' to your Content-Security-Policy. It closes a whole class of attacks for free.
Global Audience Notesβ
- Different regions may reach your site through different hosts (a regional copy, a mirror, or a translated version). Absolute base addresses can accidentally send everyone to one server, so check them.
- Offline and low-connectivity use: a page saved for offline reading can break when its base points to a faraway server. Keep important files relative to the page, or host them with it.
- Translated versions often sit in language folders (
/hi/,/es/). A base element that points to the wrong language folder sends people to the wrong version. - Do not use
target="_blank"as a default. On small phones with limited memory, many tabs make pages reload, and slow down the device. - Addresses with non-ASCII characters are converted to
%codes. Test links in your own language.
Common Mistakes to Avoidβ
- Adding
<base>"just in case". - Forgetting that
#fragmentlinks change. - More than one
<base>element. - Putting
<base>after the links and scripts it should affect. - A base element with no
hrefortarget. - Using
target="_blank"for the whole site. - A relative
hrefin the base, which is confusing. - Expecting CSS
url()to follow the base. It does not. - Not setting
base-uriin your security policy. - Putting
<base>in the body. - Copying a base from a template that points to someone else's server.
- Not testing links after the change.
Practice Timeβ
Try these in your editor:
- Write a page with five relative links, and open it. Note each address (hover to see it).
- Add
<base href="https://example.com/blog/">, and compare the addresses. - Add a
#toplink, and see where it goes with and without the base. - Read
document.baseURIin the console, with and without a base. - Add
target="_blank"to a base, then override one link with_self. - Add two base elements, and read which one is used.
- Move a
<link>above the base, and use the Network tab to see its address. - Write a Content-Security-Policy header with
base-uri 'none', and test that a base is blocked. - Rewrite your page without a base, using root-relative addresses.
- Bonus: read the base setting of a static site hosting service, and compare it with using a base element.
Quick Recapβ
Click a question to check your answer.
1. What does base href do?
It changes the address from which every relative address on the page is worked out, including links, images, scripts, stylesheets, and forms.
2. Why can #top links break with a base element?
A fragment link is measured from the base address, so #top points to the top of the base address's page, not the current page. The visitor leaves the page.
3. How many base elements can a page have?
At most one is meant to be used. If there are several, only the first with href (and the first with target) counts.
4. Does the base element change addresses inside CSS files?
No. Addresses in a CSS file are relative to that file's own address.
5. Why is the base element a security risk?
If an attacker can inject one, every relative script, link, and form on the page is redirected to their server. Add base-uri to your Content-Security-Policy to block this.
6. What is a safer alternative?
Use root-relative or absolute addresses, or your build tool's base-path setting (such as baseUrl in Docusaurus).
Key Takeawaysβ
<base href>sets the starting point for all relative addresses on the page.- It breaks
#fragmentlinks in a way that surprises many developers. <base target>sets a default target for links and forms. Do not use_blanksite-wide.- Use at most one, early in the head, with a full address.
- It does not change addresses inside CSS files.
- An injected base element can hijack scripts and forms. Add
base-urito your CSP. - Prefer root-relative addresses or your tool's base-path setting, such as Docusaurus's
baseUrl.
You have now met every element of the head. Bring it all together with Metadata Best Practices.