Links, Navigation, and URLs
The Web's Most Important Invention
The web isn't special because of HTML. It isn't special because of browsers. It's special because of hyperlinks. The ability to click a word and instantly land on a different page, a different site, a different continent's server — that's what makes the web the web.
Tim Berners-Lee invented the web in 1989, and the anchor element was there from day one. Every navigation menu, every "Read More" button, every table of contents — they're all built on this single element.
And yet, the anchor element is one of the most misused elements in HTML.
Think of a hyperlink as a door. Each door has an address written on it (the URL) and a label that tells you what's on the other side (the link text). A good door clearly states where it leads: "Kitchen", "Exit", "Conference Room B." A bad door just says "Click here" — you have no idea where you'll end up. The a element is the door. The href is the address. The link text is the label. Make every door obvious.
The Anchor Element
<a href="https://developer.mozilla.org">MDN Web Docs</a>
The a (anchor) element creates a hyperlink. The href attribute (hypertext reference) specifies the destination. The content between the tags is the link text — what users see and click.
Essential Attributes
<!-- External link opening in a new tab -->
<a href="https://example.com" target="_blank" rel="noopener noreferrer">
External Site
</a>
<!-- Link to a section on the same page -->
<a href="#features">Jump to Features</a>
<!-- Email link -->
<a href="mailto:hello@example.com">Send us an email</a>
<!-- Phone link -->
<a href="tel:+1234567890">Call us</a>
<!-- Download link -->
<a href="/report.pdf" download="annual-report.pdf">Download Report</a>
When using target="_blank", always include rel="noopener noreferrer". Without noopener, the new page can access your page's window.opener object and redirect your page to a malicious URL. Modern browsers add noopener by default for target="_blank", but adding it explicitly ensures compatibility with older browsers.
URL Anatomy
Every link points to a URL. Understanding URL structure helps you write correct paths:
https://example.com:443/courses/html?lesson=1&ref=nav#section-2
| Part | Value | Purpose |
|---|---|---|
| Protocol | https:// | How to connect (secure HTTP) |
| Host | example.com | Which server |
| Port | :443 | Which port (443 is default for HTTPS) |
| Path | /courses/html | Which resource on the server |
| Query | ?lesson=1&ref=nav | Parameters (key=value pairs) |
| Fragment | #section-2 | Which section on the page |
Relative vs. Absolute URLs
<!-- Absolute: full URL -->
<a href="https://example.com/about">About</a>
<!-- Root-relative: starts from site root -->
<a href="/about">About</a>
<!-- Relative: relative to current page -->
<a href="about">About</a>
<a href="../blog">Blog (up one level)</a>
<!-- Protocol-relative (avoid this) -->
<a href="//example.com/about">About</a>
<!-- Fragment-only: same page, different section -->
<a href="#contact">Contact Section</a>
For internal links, use root-relative paths (starting with /). They work the same regardless of which page you're on. Relative paths (without /) change meaning depending on the current page's location.
Navigation Patterns
The Nav Element
Use nav for major navigation blocks:
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/courses">Courses</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
Key points:
- Wrap the links in a
ul— a navigation menu is a list of links - Add
aria-labelwhen you have multiplenavelements on a page (main nav, footer nav, sidebar nav) - Screen readers list all
navlandmarks, so labels help users distinguish them
Skip Navigation
For keyboard users, having to tab through 50 navigation links to reach the main content is painful. Add a skip link:
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<nav><!-- Navigation links --></nav>
<main id="main-content">
<!-- Page content -->
</main>
</body>
The skip link is typically hidden visually but appears when focused (when a keyboard user tabs to it):
.skip-link {
position: absolute;
top: -100%;
left: 0;
}
.skip-link:focus {
top: 0;
}
Indicating the Current Page
<nav aria-label="Main navigation">
<ul>
<li><a href="/" aria-current="page">Home</a></li>
<li><a href="/courses">Courses</a></li>
<li><a href="/blog">Blog</a></li>
</ul>
</nav>
The aria-current="page" attribute tells screen readers which link represents the current page. You can also use it as a CSS selector: a[aria-current="page"].
Links vs. Buttons: The Rule
This distinction trips up even experienced developers:
- Links (
a) navigate somewhere — they change the URL - Buttons (
button) perform an action — they do something on the current page
<!-- Correct: navigates to a new page -->
<a href="/settings">Go to Settings</a>
<!-- Correct: performs an action -->
<button type="button" onclick="openModal()">Open Settings</button>
<!-- Wrong: link that doesn't navigate -->
<a href="#" onclick="openModal()">Open Settings</a>
<!-- Wrong: button used for navigation -->
<button onclick="window.location='/settings'">Go to Settings</button>
Why does this matter?
- Links can be opened in new tabs (middle-click, Ctrl+click). Buttons can't.
- Links are announced as "link" by screen readers. Buttons are "button." Using the wrong one confuses users.
- Links work without JavaScript (the browser handles navigation).
a href="#"with JavaScript is fragile. - Search engine crawlers follow links. They don't click buttons.
Production Scenario: Accessible Navigation
Here's a real-world responsive navigation pattern:
<header>
<a href="/" aria-label="Home — Learn Infinity">
<img src="/logo.svg" alt="" width="120" height="32">
</a>
<nav aria-label="Main navigation">
<ul>
<li><a href="/courses" aria-current="page">Courses</a></li>
<li><a href="/blog">Blog</a></li>
<li><a href="/pricing">Pricing</a></li>
</ul>
</nav>
<!-- Mobile menu toggle — it's a button because it performs an action -->
<button
type="button"
aria-expanded="false"
aria-controls="mobile-menu"
aria-label="Toggle navigation menu"
>
<span aria-hidden="true">☰</span>
</button>
</header>
Notice: the hamburger icon is a button (it toggles the menu), not a link (it doesn't navigate anywhere). The logo link has aria-label because the img alt is empty (the label provides the accessible name). The aria-expanded attribute tells screen readers whether the menu is currently open or closed.
| What developers do | What they should do |
|---|---|
| Using 'click here' or 'read more' as link text Screen readers list all links on a page. Ten links saying 'click here' are useless. Descriptive text tells users where each link goes without surrounding context | Use descriptive text: 'Read the documentation' or 'View pricing plans' |
| Using an anchor tag with href='#' and an onclick handler Links are for navigation, buttons are for actions. a href='#' breaks middle-click, adds a '#' to the URL, and confuses assistive technology | Use a button element for actions that don't navigate |
| Wrapping large blocks of content inside a single anchor Screen readers read the entire content of a link as its accessible name. A link wrapping three paragraphs creates an unbearably long announcement | Keep link content concise, or use a small clickable area with a descriptive label |
| Omitting aria-label when you have multiple nav elements Screen readers list all nav landmarks. Without labels, users hear 'navigation' three times with no way to tell them apart | Label each nav: aria-label='Main navigation', aria-label='Footer navigation' |
Challenge: Build an Accessible Navigation
Create a site header with: a logo link, a main navigation with 4 links (one is the current page), and a mobile menu toggle button. Make it fully accessible.
Show Answer
<header>
<a href="/" aria-label="DevBlog — Home">
<img src="/logo.svg" alt="" width="140" height="36">
</a>
<nav aria-label="Main navigation">
<ul>
<li><a href="/" aria-current="page">Home</a></li>
<li><a href="/tutorials">Tutorials</a></li>
<li><a href="/podcast">Podcast</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<button
type="button"
aria-expanded="false"
aria-controls="mobile-nav"
aria-label="Toggle navigation menu"
>
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
<path d="M3 6h18M3 12h18M3 18h18" stroke="currentColor" stroke-width="2"/>
</svg>
</button>
</header>Accessibility details:
- Logo link uses
aria-labelfor a descriptive accessible name - Logo
imghasalt=""because thearia-labelon the parent link provides the name - Current page marked with
aria-current="page" - Mobile toggle is a
button, not a link (it performs an action) aria-expandedcommunicates open/closed state to screen readersaria-controlsassociates the button with the menu it controls- SVG icon has
aria-hidden="true"— the button's label comes fromaria-label
- 1Links navigate (change URL), buttons act (do something on the page) — never use a href='#' for actions
- 2Always use descriptive link text — 'click here' is meaningless to screen readers listing all links
- 3Add rel='noopener noreferrer' when using target='_blank' for security
- 4Use root-relative paths (/about) for internal links — they work regardless of the current page's location
- 5Label multiple nav elements with aria-label so screen reader users can tell them apart