Links and Navigation
The anchor tag in full — relative vs absolute paths, targets, anchor links within a page, and building real navigation.
<a> — The Element the Entire Web Is Built On
The anchor tag, <a>, is what turns "documents" into "the web" — a network of pages connected to each other by clickable links. Its one required piece is the href attribute (short for "hypertext reference"), which tells the browser where the link should actually go.
<a href="/about">About us</a>Everything between the opening and closing <a> tags becomes clickable — that can be plain text, as above, but it can just as easily be an image, a heading, or an entire card made of several nested elements, as long as the nesting rules HTML allows are respected.
<a href="/products/trail-runner-gtx" class="product-card">
<img src="/img/trail-runner.jpg" alt="Trail Runner GTX hiking shoe">
<h3>Trail Runner GTX</h3>
<p>$139</p>
</a><div> or <span> with a click handler attached in JavaScript when a real <a href> would do the job. A real anchor gets keyboard focus automatically, supports "open in new tab" and "copy link address" from a right click, and is announced correctly by screen readers — all for free, with zero extra code. A <div> pretending to be a link gets none of that unless you manually rebuild it yourself, and most homegrown attempts to do so are incomplete.Absolute, Relative, Root-Relative, and Protocol-Relative — Every href Format
The value you put inside href can take several different forms, and each one is resolved by the browser differently. Getting comfortable telling them apart on sight is a genuinely practical skill — it is the difference between a link that correctly follows a site wherever it moves and one that silently breaks the moment a folder gets renamed.
<a href="https://chaduvuko.com/learn/html-css">HTML & CSS Track</a>
<!-- Full protocol + domain + path. Always points to the exact same
place, no matter what page this link is written on. Required for
linking to a DIFFERENT site than the one you're currently on. --><!-- If the current page is /learn/html-css/links-navigation -->
<a href="images-media">Next lesson</a>
<!-- Resolves to /learn/html-css/images-media — relative to the
CURRENT folder, not the site root. -->
<a href="../python/control-flow">A page in a sibling folder</a>
<!-- ../ steps up one folder level, exactly like a file system path --><a href="/learn/html-css/images-media">Next lesson</a>
<!-- The leading / means "start from the site's root domain," no
matter which folder the current page happens to live in. This is
the most common, and generally safest, choice for internal links
on a real site — it does not break if the current page moves to
a different folder later. --><a href="//cdn.example.com/library.js">Some external resource</a>
<!-- No "https:" at all — the browser automatically uses whatever
protocol (http or https) the current page was loaded with. Once
common for CDN links; largely obsolete now that essentially every
site is served over HTTPS exclusively, but you will still see it
in older codebases and it's worth recognizing on sight. -->For links within your own site, root-relative (/path/to/page) is generally the most reliable everyday default — it survives the current page moving to a different folder, unlike a plain relative link, and it does not hardcode a specific domain the way an absolute URL does, which matters when the same codebase runs on a local dev server, a staging environment, and production, each with a different domain.
href="about" on a page whose own URL has a trailing slash difference than expected. Because relative URLs resolve against the current page's exact folder, a link that works correctly from /products/ can resolve to entirely the wrong path from /products (no trailing slash) — the two look almost identical but resolve differently. Root-relative links sidestep this whole category of bug, since they never depend on the current page's own path at all.Opening Links in a New Tab — And the Security Hole It Can Quietly Open
The target attribute controls where a link opens. target="_blank" is by far the most common value you will use, opening the link in a new tab or window instead of navigating the current one.
<a href="https://example.com" target="_blank">External site</a>On its own, this line has a real, well-documented security implication that is easy to miss entirely: the page that opens in the new tab is, by default, given a live JavaScript reference back to the page that opened it, through window.opener. A malicious destination page can use that reference to silently redirect the original tab — the one still showing your site — to a phishing page, all while its own new tab looks completely normal to the user. This is a real attack pattern with a name: tabnabbing.
<a href="https://example.com" target="_blank" rel="noopener noreferrer">
External site
</a>rel="noopener" is the part that actually closes the hole — it prevents the new page from getting that window.opener reference back to your page at all. noreferrer goes one step further and also stops the browser from sending your page's URL in the Referer header of the request to the new page, which some teams prefer for privacy reasons on top of the security fix. Modern browsers have quietly started applying noopener behavior to target="_blank" links automatically in some cases — but relying on that default rather than writing rel explicitly is not a safe practice to build a habit around, since it is not guaranteed or consistent across every browser and context.
target="_blank" rel="noopener noreferrer" as one inseparable unit whenever you link to a page you do not fully control — this comes up constantly in real code review, and is one of the most commonly flagged security issues in front-end pull requests specifically because it is so easy to write the target half and simply forget the rel half.Linking to a Specific Point Within a Page — id Targets
A link can point at a specific location within a page, not just at another page entirely, by referencing an element's id attribute with a # prefix. This is exactly how "back to top" links and a table of contents that jumps to the right section both work.
<nav>
<a href="#pricing">Pricing</a>
<a href="#faq">FAQ</a>
</nav>
...
<section id="pricing">
<h2>Pricing</h2>
...
</section>
<section id="faq">
<h2>Frequently Asked Questions</h2>
...
</section>Clicking <a href="#pricing"> scrolls the browser directly to the element whose id is exactly pricing — no JavaScript required at all, this is native browser behavior. You can also link to an anchor on another page by combining a path with a fragment: href="/pricing#faq" navigates to the pricing page and then jumps straight to its FAQ section once loaded.
<a href="#top">Back to top</a>
<!-- "#" alone (or "#top" when an element with id="top" exists near the
very start of the page) scrolls all the way to the top of the
document — a very common footer pattern on long pages. -->id values must be unique within a page — exactly one element per page can carry any given id. Two elements sharing the same id is invalid HTML, and it produces genuinely unpredictable results for an anchor link targeting it (usually jumping to whichever one the browser happens to find first, which is not something you should rely on).download, mailto:, and tel: — Links That Do Something Other Than Navigate
Not every anchor tag is meant to load another page. Three specific patterns come up constantly in real work.
<a href="/files/pricing-sheet.pdf" download>Download pricing sheet (PDF)</a>
<!-- Give it a specific suggested filename, different from the source file: -->
<a href="/files/pricing-sheet.pdf" download="Trailhead-Pricing-2026.pdf">
Download pricing sheet
</a>Without the download attribute, clicking a link to a PDF or image typically opens it directly in the browser tab instead of saving it — exactly the behavior you usually want for a normal link, but not what you want for a "download our brochure" button. The download attribute overrides that, forcing a save dialog instead.
<a href="mailto:support@trailheadboots.com">Email support</a>
<a href="mailto:support@trailheadboots.com?subject=Order%20Question&body=Hi%20team,">
Email us about an order
</a>
<a href="tel:+15125550142">Call (512) 555-0142</a>mailto: links open the visitor's default email client with the "to" field pre-filled, and optionally a pre-filled subject and body — note that spaces and special characters in those extra query parameters need URL-encoding (%20 for a space, as shown above). tel: links trigger a phone call on devices that can place one — mobile phones directly, and desktop browsers that have a calling app (like FaceTime or a VOIP client) configured to handle it.
mailto: and tel: genuinely matter for mobile users specifically — on a phone, tapping a phone number formatted as a real tel: link starts a call with zero extra steps, while the same number as plain, unlinked text requires the user to manually copy it and switch to their phone app themselves. This is a small addition with an outsized effect on real conversion for any business-contact page.Building a Real, Semantic Navigation Menu
Putting everything in this module together: a real navigation menu is a <nav> landmark (from the previous module) containing a <ul> of links — not a row of bare <a> tags separated by spaces, and not a row of <div>s.
<header>
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/shop">Shop</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
</header>Wrapping each link in a list item is not just a styling convenience — a list of links is announced by screen readers as exactly that, "a list of 4 items," giving a user a clear sense of how many navigation options exist before they even start moving through them one at a time. A bare row of links with no list structure gives no such count. The aria-label="Main navigation" attribute is worth adding whenever a page has more than one <nav> region (a primary menu and, separately, a footer link list, for instance) so that assistive technology can distinguish between them by name rather than announcing two unlabeled, identical-sounding "navigation" landmarks.
<nav aria-label="Main navigation">
<ul>
<li><a href="/" aria-current="page">Home</a></li>
<li><a href="/shop">Shop</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<!-- aria-current="page" tells assistive tech "this is the page the
user is currently on" — commonly also targeted by CSS to visually
highlight the active nav item, e.g. [aria-current="page"] { ... } -->aria-current="page" is a genuinely underused, high-value attribute — it gives you a single, semantic hook that solves both the accessibility problem (announcing the current page to assistive tech) and the visual-styling problem (a CSS attribute selector to highlight the active link) at the same time, without needing a separate class="active" that has to be kept in sync manually.A Security Review Flags a Partner-Links Page at a Miami Fintech Startup
Ahead of a public launch, a Miami fintech startup runs a mandatory third-party security review of its marketing site. The review flags a "resources" page listing links out to a dozen partner integrations and press mentions — every one of them opening with target="_blank", with no rel attribute at all.
Why this specific finding matters for a fintech company
The reviewer explains the tabnabbing risk directly: any of those dozen external destinations — including ones the company does not fully control, like a press article hosted on a third-party news site — could, in principle, use window.opener to silently redirect the original Chaduvuko-style marketing tab to a convincing fake login page while the user is reading the article in the newly opened tab. For a financial services company specifically, where the "original tab" the attacker would be redirecting is exactly the kind of page a user might later try to log into, this is treated as a genuine, launch-blocking risk rather than a minor code-quality nitpick.
<a href="https://partner-press-site.com/article" target="_blank">
Read the feature
</a><a href="https://partner-press-site.com/article"
target="_blank"
rel="noopener noreferrer">
Read the feature
</a>The engineering team ships the fix as a global lint rule rather than a one-time manual patch — an ESLint rule flagging any target="_blank" anchor missing rel="noopener", so the mistake cannot silently reappear the next time someone adds a new external link months later. This is exactly the kind of small, easy-to-miss HTML detail that a security review specifically exists to catch before launch, precisely because it produces zero visible symptoms during normal QA — the links all "work" perfectly fine from a functional testing perspective.
Four Misconceptions About Links and Navigation
5 Interview Questions — With Complete Answers
Link Mistakes Beginners Make Constantly
Errors and Symptoms You Will Hit — And Exactly Why
🎯 Key Takeaways
- ✓The anchor tag (<a href>) is the foundation of the entire web — prefer it over a styled div/span with a click handler for anything that genuinely navigates somewhere, to get free keyboard focus, right-click options, and screen-reader support.
- ✓Relative hrefs resolve against the CURRENT page's folder and can break when a page moves. Root-relative hrefs (starting with /) always resolve from the site root and are the safer everyday default for internal links.
- ✓target="_blank" without rel="noopener noreferrer" leaves a real security hole (tabnabbing) — the new page can get a JavaScript reference back to the page that opened it. Treat the two attributes as inseparable.
- ✓An href fragment (#some-id) scrolls natively to the element with a matching id — no JavaScript required. ids must be unique per page.
- ✓download forces a file to save instead of opening in-browser; mailto: and tel: open the user's email client or dialer directly, which matters a lot for real mobile conversion.
- ✓A real nav menu is a <nav> landmark wrapping a <ul> of links, not a bare row of <a> tags — the list structure gives assistive tech an item count, and aria-current="page" marks the active link for both accessibility and CSS styling.
What comes next
Module 05 covers images and media in full — the img tag and why alt text is never optional, figure/figcaption, audio and video, the source element, and lazy loading.
Module 05 → Images and MediaDiscussion
0Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.