Link Anti-patterns
Links are most useful when they are discoverable and have a predictable outcome.
The Problem
When links are disguised in another tag or are improperly formatted, they become harder to find and may have unexpected outcomes.
The Solution
Anything that behaves like a link should use an <a>
tag with an href, anything else should use a <button>
Related Articles
- MDN - The Anchor element: Accessibility Concerns
- Udacity - Link Text
- A11y Project - Quick tip: Creating valid and accessible links
Live Examples
Before illustrates the problem, After illustrates the solution. Click the header to see it larger in a modal.
Please note that this Before example contains inaccessible code, use this link to skip to the After Live Examplebefore
after
Code Comparison
Code diff between the before and after examples above to show the changes necessary. To copy the final source click on the 'after' path link before the diff.
source
Comparing /examples/navigation/link-anti-patterns/before/index.html to /examples/navigation/link-anti-patterns/after/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Accessibility Solutions - Navigation - Link Anti-patterns</title>
<link rel="stylesheet" href="../../../presentation.css" />
<link rel="stylesheet" href="link-anti-patterns.css" />
</head>
<body id="top">
<h1>Links Anti-pattern examples</h1>
<h2>Using Improper Tags</h2>
<p>
We lose discoverability when using a tag other than
<code><a></code> for links, they're not in the tabindex nor in the
list of links in VoiceOver Rotor.
</p>
<span class="link span-linka href="#bottom" onclick="scrollToBottom(event)"
>This isa span pretending to be a linklink to the bottom of the page</span
>
<h2>Link without an href</h2>
<p>
Links that don't have an href and rely on JavaScript are not fully
discoverable either, they're often removed from the tabindex.
</p>
<aclass="linkhref="#bottom" onclick="scrollToBottom(event)"
>This is a link withoutan href fallback</a
>
<h2>Interactive controls that don't behave like a link</h2>
<p>
The opposite issue as above, when a link has an <code>href="#"</code> or
similar, chances are it'd be better suited as a button.
</p>
<a class="link" href="#"button onclick="doSomething()">
>This is alinkbutton thatshould be adoes something
</button</a>
<h2>Linked image without alt text</h2>
<p>
Without alternative text, a linked image is not fully discoverable either.
</p>
<a href="#bottom" onclick="scrollToBottom(event)">
<img src="/img/logo.svg" width="180" alt="Accessibility Solutions" />
</a>
<div class="super-long-space"></div>
<a href="#top" id="bottom" onclick="scrollToTop(event)"
>Going up? Back to top</a
>
<script src="link-anti-patterns.js"></script>
</body>
</html>
styles
Comparing /examples/navigation/link-anti-patterns/before/link-anti-patterns.css to /examples/navigation/link-anti-patterns/after/link-anti-patterns.css
.link {
color: #dc3542;
font-weight: bold;
transition: all 0.3s ease;
}
.link:hover,
.link:focus {
color: #d21a28;
cursor: pointer;
text-decoration: underline;
}
javascript
Comparing /examples/navigation/link-anti-patterns/before/link-anti-patterns.js to /examples/navigation/link-anti-patterns/after/link-anti-patterns.js
function doSomething() {
alert('did something');
}
function scrollToBottom(e) {
e.preventDefault();
const anchor = document.querySelector(e.currentTarget.getAttribute('href'));
window.scrollTo({ top:document.body.scrollHeightanchor.offsetTop, behavior: 'smooth' });
}
function scrollToTop(e) {
e.preventDefault();
window.scrollTo({ top: 0, behavior: 'smooth' });
}