Skip to content

Links, Navigation, and URLs

beginner13 min read

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.

Mental Model

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>
Common Trap

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.

Quiz
Why should you add rel="noopener" when using target="_blank"?

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
PartValuePurpose
Protocolhttps://How to connect (secure HTTP)
Hostexample.comWhich server
Port:443Which port (443 is default for HTTPS)
Path/courses/htmlWhich resource on the server
Query?lesson=1&ref=navParameters (key=value pairs)
Fragment#section-2Which 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.

Quiz
On a page at /courses/html/basics, where does this link point: href='../css'

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-label when you have multiple nav elements on a page (main nav, footer nav, sidebar nav)
  • Screen readers list all nav landmarks, 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"].

Quiz
What is the purpose of aria-current="page" on a navigation link?

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.
Execution Trace
User clicks link
Browser checks href attribute
If href is a URL, browser navigates. If href='#', nothing useful happens
Browser navigates
HTTP request sent to href destination
This is the default link behavior — no JavaScript needed
New page loads
URL in address bar changes
Back button works, page is bookmarkable, crawlers can follow
Contrast: button click
Click event fires, no navigation
Buttons trigger JavaScript actions — they don't change the URL

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">&#9776;</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 doWhat 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-label for a descriptive accessible name
  • Logo img has alt="" because the aria-label on 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-expanded communicates open/closed state to screen readers
  • aria-controls associates the button with the menu it controls
  • SVG icon has aria-hidden="true" — the button's label comes from aria-label
Key Rules
  1. 1Links navigate (change URL), buttons act (do something on the page) — never use a href='#' for actions
  2. 2Always use descriptive link text — 'click here' is meaningless to screen readers listing all links
  3. 3Add rel='noopener noreferrer' when using target='_blank' for security
  4. 4Use root-relative paths (/about) for internal links — they work regardless of the current page's location
  5. 5Label multiple nav elements with aria-label so screen reader users can tell them apart