Links and URLs

Link anywhere on the web correctly, and understand how a browser resolves a path.

06of 22
≈ 12Min read
8Parts

The element the web is built on

<a href="…"> turns text into a destination. The text inside it is what a reader clicks and what a screen reader announces, so it has to make sense on its own: many people navigate by listening to a list of every link on the page. "Read the CSS guide" works there; "click here" does not.

five kinds of destination
<a href="/learn/css/">Another page on this site</a>
<a href="https://developer.mozilla.org/">Another site</a>
<a href="#forms">A heading further down this page</a>
<a href="mailto:hello@example.com?subject=Doors">Start an email</a>
<a href="tel:+994501234567">Call, on a phone</a>

What a URL is made of

  • scheme — https: almost always. mailto:, tel: and # are also schemes of a sort.
  • host — the domain. A different host is a different site to the browser, and that is what "cross-origin" means.
  • path — where on that host. Case matters on most servers.
  • query — ?key=value&key2=value2. Filters, searches, tracking.
  • fragment — #id. Never sent to the server; the browser scrolls to the element with that id.
the parts
https://domvybe.com:443/learn/html/links/?from=home#urls
 scheme    host       port  path              query      fragment

Absolute, root-relative, relative

Written asResolves toUse when
https://site.com/a/bExactly thatAnother site
//site.com/aThe current scheme + that hostAlmost never now — just write https
/about/The site root + /about/Anywhere in your own site — the safe default
about/The current folder + about/You are certain of the current folder
../about/One folder upRarely; it breaks as soon as a page moves
?page=2This page with a new queryPagination and filters
#topThis page, scrolledIn-page navigation
The trailing slash changes the answer

/about and /about/ are different URLs. If your page is served from /about/index.html, always link to /about/ — otherwise every relative link inside that page resolves one level too high, and you get a page with broken images that works fine locally.

Anchors inside a page

Give the target an id and link to #that-id. The browser scrolls to it, adds it to the history, and puts it in the address bar so the position can be shared.

Two things make this much better: scroll-margin-top on the target so a sticky header does not cover it, and moving focus, not just the scroll position, so keyboard users continue from the right place.

stop the header covering the heading
:target, h2 {
  scroll-margin-top: 96px;
}

Opening in a new tab

target="_blank" opens a new tab. Pair it with rel="noopener": without it the opened page receives a reference to yours through window.opener and can navigate it somewhere else — a real phishing route. Modern browsers imply noopener; older ones do not, and the attribute costs nothing.

Do not use it for links inside your own site. You are removing the back button from someone who expected it.

an external link
<a href="https://toolrack.app" target="_blank" rel="noopener">
  Toolrack <span aria-hidden="true">↗</span>
</a>

rel values worth knowing

ValueMeaning
noopenerThe new page gets no reference to this one.
noreferrerDo not send the Referer header. Implies noopener.
nofollowDo not pass ranking credit — for user-submitted or paid links.
sponsored / ugcMore precise versions of nofollow.
externalPurely informative, often used as a CSS hook.

Downloads

download asks the browser to save the file rather than display it, and can rename it. It only works for files on your own origin.

save, do not open
<a href="/downloads/starter.zip" download="domvybe-starter.zip">
  Download the starter (1.2 MB, ZIP)
</a>

Say what the file is, how big it is and what format. A link that silently starts a 40 MB download is a bad surprise.

  • <a> with no href is not a link and is not focusable. If it does something, it is a <button>.
  • <a href="#" onclick="…"> navigates to the top of the page if your script fails. Use a button.
  • A whole card wrapped in one link is fine — but do not nest a second link inside it; that is invalid and unreachable by keyboard.

Practice