File Paths & URLs
Every href, every src and every stylesheet link contains an address. Get it slightly wrong and you see a broken image, an unstyled page or a "404 Not Found" error. Most of these bugs come from a handful of misunderstandings about paths.
You already wrote simple relative links in HTML Links. In this lesson you will learn the parts of a URL, the four ways to write a path, exactly how the browser turns a path into a full address, how to handle spaces and Hindi characters, and why a site that works on your Windows laptop can break on a Linux server.
The parts of a URL
A URL (Uniform Resource Locator) is a full web address. It has up to six parts:
| Part | Example | Meaning |
|---|---|---|
| Scheme | https: | How to fetch it (https, http, mailto, tel...) |
| Host | shop.example.in | Which server, by domain name |
| Port | 8080 | Which "door" on the server; usually hidden because https uses 443 by default |
| Path | /books/class-12/physics.html | Which file or page on that server |
| Query | ?lang=hi&page=2 | Extra settings as name=value pairs |
| Fragment | #chapter-3 | A place inside the page; never sent to the server |
The browser can split any URL into these parts for you. Edit the address in the box and press the button.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>URL parts</title>
<style>
input { width: 100%; max-width: 560px; }
td { padding: 3px 10px; border-bottom: 1px solid #ddd; }
</style>
</head>
<body>
<label for="address">Address</label><br>
<input id="address" value="https://shop.example.in:8080/books/class-12/physics.html?lang=hi&page=2#chapter-3">
<button type="button" id="split">Split it</button>
<table id="parts"></table>
<script>
const show = () => {
const table = document.querySelector("#parts");
table.replaceChildren();
try {
const url = new URL(document.querySelector("#address").value);
const rows = { protocol: url.protocol, hostname: url.hostname, port: url.port || "(default)",
pathname: url.pathname, search: url.search, hash: url.hash,
"lang value": url.searchParams.get("lang") };
for (const [name, value] of Object.entries(rows)) {
table.insertRow().append(Object.assign(document.createElement("td"), { textContent: name }),
Object.assign(document.createElement("td"), { textContent: value }));
}
} catch {
table.insertRow().insertCell().textContent = "That is not a complete URL. Did you forget https://?";
}
};
document.querySelector("#split").addEventListener("click", show);
show();
</script>
</body>
</html>Try removing https://: the browser can no longer understand the address on its own. That is exactly why href="www.example.in" does not link to another website.
Four ways to write a path
| Kind | Example | Starts from |
|---|---|---|
| Absolute URL | https://cdn.example.in/logo.svg | Nowhere: it is complete |
| Root-relative | /css/style.css | The root (top folder) of the current site |
| Document-relative | images/logo.svg, ../index.html | The folder of the current page |
| Fragment or query only | #fees, ?page=2 | The current page itself |
Use absolute URLs for other websites. For your own site, document-relative paths work everywhere, even when you open files straight from your disk. Root-relative paths are shorter on big sites with deep folders, but they need a web server, as the warning in HTML Links explains.
How the browser resolves a path
The browser never requests ../index.html from a server. It first combines the path with the address of the current page, called the base URL, to make a complete URL. The rules are simple:
- A plain name, or one starting with
./, means "in the same folder as this page". - A folder name followed by
/goes down into that folder. - Each
../goes up one folder. At the top of the site, extra../steps are ignored. - A leading
/jumps to the root of the site.
Suppose the current page is https://www.example.in/courses/web/intro.html. Type paths into this tool and watch where they lead.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Path resolver</title>
<style>
input { width: 100%; max-width: 480px; margin-bottom: 8px; }
output { display: block; font: 15px monospace; background: #f3f3f3; padding: 8px; }
</style>
</head>
<body>
<label for="page">Current page</label><br>
<input id="page" value="https://www.example.in/courses/web/intro.html"><br>
<label for="path">Path written in href or src</label><br>
<input id="path" value="../python/intro.html">
<output id="result"></output>
<p>Try: <code>lesson-2.html</code>, <code>images/logo.svg</code>, <code>../../index.html</code>,
<code>/css/style.css</code>, <code>#quiz</code>, <code>my notes.html</code></p>
<script>
const resolve = () => {
try {
const page = document.querySelector("#page").value;
const path = document.querySelector("#path").value;
document.querySelector("#result").textContent = new URL(path, page).href;
} catch {
document.querySelector("#result").textContent = "The current page must be a full URL.";
}
};
document.querySelector("#page").addEventListener("input", resolve);
document.querySelector("#path").addEventListener("input", resolve);
resolve();
</script>
</body>
</html>Notice what happens with my notes.html: the browser quietly changes the space to %20. More about that below.
The trailing slash matters
The base folder is everything up to the last slash of the current address. So these two addresses behave differently:
- On
https://example.in/courses/, the pathpython.htmlbecomeshttps://example.in/courses/python.html. - On
https://example.in/courses, with no final slash,coursesis treated as a file name, sopython.htmlbecomeshttps://example.in/python.html.
Put both addresses into the resolver to see it. If relative links work on one URL of a page but break on another, check the trailing slash first.
Paths inside CSS and JavaScript files
A path written inside a stylesheet, such as background-image: url("../images/pattern.svg"), is relative to the stylesheet file, not to the HTML page. A path given to fetch() in an ordinary script is relative to the page, while a path in a module import is relative to the module file.
/* This file is css/style.css, so ../ climbs out of the css folder */
.hero { background-image: url("../images/hero.svg"); }Spaces and special characters
A URL may only contain a limited set of plain characters. Anything else, such as a space, ₹ or Devanagari letters, is sent as percent-encoded bytes: a % followed by two hexadecimal digits for each byte. A space becomes %20, and & becomes %26.
Some characters have a special job, so they must be encoded when they are part of a name: ? starts the query, # starts the fragment, & separates query pairs and % starts an encoding. In JavaScript, encodeURIComponent() encodes a value safely.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>URL encoding</title>
</head>
<body>
<label for="text">Text to put in a URL</label>
<input id="text" value="fee structure 2026.pdf">
<p>Encoded: <code id="encoded"></code></p>
<p>Try <code>Q&A</code>, <code>₹1,299</code>, <code>50% off</code> or <code>नमस्ते</code>.</p>
<script>
const box = document.querySelector("#text");
const update = () => {
document.querySelector("#encoded").textContent = encodeURIComponent(box.value);
};
box.addEventListener("input", update);
update();
</script>
</body>
</html>Browsers display Hindi and other scripts readably in the address bar, but send the encoded form to the server. Inside query strings created by forms, a space is often written as + instead of %20, as you saw in HTML Forms.
The simplest fix is to avoid the problem: name files with lowercase letters, digits and hyphens only, such as fee-structure-2026.pdf.
Upper and lower case
The scheme and domain name are not case-sensitive: HTTPS://EXAMPLE.IN is the same site as https://example.in. The path is a different story. Most web hosting runs on Linux, and Linux treats Logo.png, logo.png and logo.PNG as three different files.
This catches many beginners using XAMPP on Windows. Windows ignores case, so <img src="images/Logo.png"> happily shows logo.png on your laptop. After you upload the site, the same image is broken. Keep every file and folder name lowercase and type paths exactly as the files are named.
Paths that only work on your computer
<!-- Wrong: these point at YOUR disk, which visitors cannot reach -->
<img src="C:\Users\Priya\Desktop\site\images\logo.png" alt="Logo">
<img src="file:///C:/Users/Priya/Desktop/site/images/logo.png" alt="Logo">
<!-- Right: a path relative to the page, with forward slashes -->
<img src="images/logo.png" alt="Logo">Editors sometimes insert full disk paths when you drag a file in. The page looks fine on your machine and broken for everyone else. Also note that URLs always use forward slashes /; the backslash \ belongs to Windows file paths.
Common mistakes
- Capital letters in file names. Works on Windows, breaks on a Linux server. Use lowercase.
- Spaces in file names. They become
%20and are easy to mistype. Use hyphens. - Disk paths such as
C:\.... Use relative paths with forward slashes. - Forgetting that CSS paths start from the CSS file.
url("images/a.svg")insidecss/style.csslooks forcss/images/a.svg. - Ignoring the trailing slash.
/coursesand/courses/resolve relative paths differently.
Key points
- A URL has a scheme, host, optional port, path, query and fragment.
- Absolute URLs are complete; root-relative paths start with
/; document-relative paths start from the current page's folder. - The browser resolves every relative path against a base URL;
../climbs one folder and the trailing slash decides the base folder. - Paths inside a stylesheet are relative to the stylesheet file.
- Spaces and special characters are percent-encoded (
%20); avoid them in file names. - Paths are case-sensitive on most servers, so name everything in lowercase.
Exercise
Your site has index.html, a folder css/ with style.css, a folder images/ with school-logo.svg, and a folder events/annual-day/ containing index.html. Write the <link> and <img> elements needed in events/annual-day/index.html to load the stylesheet and the logo, plus a link back to the home page, all using document-relative paths. Then write the CSS rule in style.css that uses school-logo.svg as a background image.
Show solution
<!-- events/annual-day/index.html -->
<link rel="stylesheet" href="../../css/style.css">
<img src="../../images/school-logo.svg" alt="Kendriya Vidyalaya Rohtak logo">
<a href="../../index.html">Back to the home page</a>/* css/style.css */
.banner { background-image: url("../images/school-logo.svg"); }The page is two folders deep, so it needs ../../ to reach the site root. The stylesheet is only one folder deep, and its paths start from its own folder, so it needs a single ../.
Quick Quiz
1. On the page https://example.in/shop/bags/index.html, where does href="../shoes/" lead?
The page's folder is /shop/bags/; ../ climbs to /shop/, then the path goes into shoes/.
2. Which part of a URL is never sent to the server?
The fragment only tells the browser where to scroll inside the page.
3. Your images work in XAMPP on Windows but break after uploading to the host. What is the most likely cause?
Windows ignores case, but Linux servers treat Logo.png and logo.png as different files.
4. What does a space in a URL path become?
URLs percent-encode a space as %20 (and forms often use + in query strings).
Learn HTML with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
