Accessible Card Links
(Yet another) definitive guide on how to build a card that works like a link. Think product links or blog posts. Because there are too many doing it wrong.
My girlfriend has been doing a lot of accessibility research lately and has looked at a lot of websites as guidance for the European accessibility act. We’ve been talking about it a lot and most websites do card links wrong.
What is wrong
- Multiple links with the same target. Some screenreader users will create link lists and that noise at this point.
- Wrapping the whole card in a link. That’s better, but creates a LONG link text. It’s also confusing when you want another link INSIDE the card.
- Not using a link at all. Well, what should I say. The button vs link debate is another topic.
Doing it right
So what we want:
- Good semantic HTML structure
- One link with clear link text
- The whole card should still be clickable and have visible hover and focus styles
The markup
The markup is from our very own nordcode “component library”. It’s more of a documentation and a style package.
Here’s the full docs on clickable cards
<article class="nc-clickable-card nc-stack";
padding: var(--spacing-base);">
<img src="/preview.jpg" alt="">
<h2>
<a href="#" data-link="main">Here we go again</a>
</h2>
<p>After seeing to many inaccessible cards, it was time to warm the topic up again.</p>
<div class="nc-cluster nc-hint">
<time>Today</time><span>-</span><span>Joshua</span>
</div>
</article>
and this is the actual CSS we use:
:where(.nc-clickable-card) {
cursor: pointer;
position: relative;
&:focus-within,
&:hover {
outline: var(--border-width-medium) solid var(--color-brand-primary-base);
}
& a[data-link="main"] {
text-decoration: none;
&:focus-within:focus-visible,
&:hover {
outline: none;
}
&:before {
content: "";
position: absolute;
inset: 0;
}
}
& a[data-link="extra"] {
position: relative;
}
}
Keep the data-link attribute in mind, we’ll return to it later. For your own project, you can also ignore that and change the main link to a simple a rule.
Why it works
If you looked at the code on the page, you’ll notice that the whole card is focussable, clickable and has a hover effect. Well, it appears to have it.
The actual link is inside the article’s title. and only that is focused. The rest is CSS.
By using position: relative and an pseudo-element that spans the whole card, the whole card becomes clickable. The rest is leveraging :focus-within. That’s it.
Extras
Let’s say you want an additional link to the article’s author. Easy. Add it to the cards and use data-link="extra". By applying position: relative to the extra-link, it remains clickable.
If the link comes before the main link, you’ll have to use z-index, to place it above the clickable link.
An optional Read more faux button or link can be added. You can apply your own styles there. It’s probably a good idea to add aria-hidden="true" to it, to hide it from screen readers.
If you really want, you can also add some screen reader only text before the link target, like “Read the article about:” by using a .sr-only class.
That’s it. Now go and create better cards. Thanks for reading!