What's in a link

Links make the web work—they're a basic component of every website, and join individual pages together to create a complex content network. As web-designers and developers it is our job to create links that work well for all users of our website, and I want to help make that job simpler.

I've spent a lot of time researching how to create good, usable links, and realised two things—it's a very hard thing to do, and the relevant information is spread out all over the web. What I wanted was a single document that drew together all of these recommendations based on user research and web standards to help web-developers and designers make their sites more accessible for everyone.

Our links should be easily usable and accessible to as many people using our website as humanly possible. Much of the web is 'accessible by default', and links are no exception to this rule—without any extra work, an HTML document will have links which are;

  • Visually recognisable (blue, underlined)
  • Accessible with the keyboard (tabindex)
  • Denoted on hover (cursor)
  • Denoted on focus (outline)
  • Denoted as visited (purple)
  • Denoted as active (red)

They work equally well on desktop and on mobile, are simple, obvious, and stand out from the surrounding content. If nothing else is achieved, maintaining these properties will make your site remarkably accessible.

So what should we be thinking about when marking up and styling our links?

There are a range of states to show user interaction with links. However, these states are only as useful as the styling associated with them. Using reset stylesheets commonly results in these being stripped away, so use normalise stylesheets instead and make sure any other styling is added back as needed.

The available states are;

  • :link—an unvisited link
  • :visited—a visited link
  • :hover—a link being interacted with using a pointing device (e.g. a mouse)
  • :focus—a link being interacted with using a keyboard or similar non-pointing device
  • :active—being activated by the user. In practice this is the time during which a keyboard, mouse button, or touch input is between the relevant down and up events (e.g. keydown and keyup)

In addition to these we also have the base state of the link, before any user interaction.

So what are the best practices for styling links? Research by the Nielsen Norman Group recommends that links have both a unifying colour and underline to signal their intent. Whilst the underline can be omitted when the links are identified by their context (such as in a menu), for links within content it gives a strong visual cue that separates them from surrounding text and makes them much simpler to scan. My colour-sense isn't the best, and on smaller screens or in poor light I can struggle to pick out non-underlined links from their context without some scrubbing.

Links within content should also have styles which are sufficiently different from any other text styles. If you're underlining links, then you should avoid defining (or giving your editors) other text styles that use an underline. Another common style to avoid is a dotted underline, since this is the default style for the <abbr> tag in Firefox and Opera.

For links which aren't nested in content, you have some more flexibility. Additional research on styling clickable elements gives some other great cues: make sure your links are sufficiently distinct from your non-link elements; make all elements (text, images, etc.) associated with a call-to-action clickable; and if in doubt add additional visual clues (such as arrows) to indicate clickability.

The proliferation of touch-screen devices has changed the way that developers should treat the hover state In the past it has been used to simplify the display of non-content links, often revealing extra information. Touch devices have varying support for the hover state and will primarily use the active state when a link is clicked. As such, avoiding the hover state as a link enhancement for anything more than decoration is encouraged.

To test the overall accessibility of your pages, there are automatic tools to do a lot of the work. In the past I've used the WAVE accessibility tester, but there are also Grunt plugins and services like Tenon.io to allow you increasing levels of automation with CI.

Pseudo-classes

Pseudo-classes are used to target links in different states. Understanding the purpose of different pseudo-classes will let you style links appropriately and predictably for users of your website, improving their usability.

As noted above, the available pseudo-classes are link, visited, hover, focus, and active. They follow the LHVA (link, hover, visited, active) order of precedence, and should be written in this order in your stylesheet for proper precedence. focus isn't explicitly defined in the order, but should be placed before, after, or with your hover state (as I'll explain below).

The link pseudo-class targets unvisited links, and is the opposite of visited. For link to apply, the element must have an href attribute. This pseudo-class forms your base styling for links.

:visited

The visited pseudo-class targets visited links. As with link, visited requires the element to have an href attribute to apply.

The visited pseudo-class seems to have fallen out of favour in recent times. One reason may be that it's not always useful, and it isn't obvious when it should be used. I'd recommend visited is used for sites with frequent new content, such as blogs or news sites. In this context it is helpful to the user to be able to see at a glance which links they've already visited.

Conversely, it's not useful for sites or regions with largely static content, such as a brochureware site or your main navigation. These links will be visited repeatedly, and notifying the user that they've visited them before doesn't improve the utility of the site.

:hover

The most commonly used pseudo-class, hover targets links when the user mouses over them. In recent times the way that developers use hover has changed due to the proliferation of touch-screen devices, which generally don't respect hover.

The current best practice is that the styling of your hover state should not be used to reveal extra information, since you should assume that some users will not have access to it. hover should instead only be used to highlight the link on interaction with a mouse or pointing device.

:focus

The least commonly-used (or most misunderstood) pseudo-class, focus targets elements which have focus—defined as accepting a input event, most commonly from a keyboard or mouse. For links this means that it would activate when hitting return on the keyboard. The simplest ways to give a link focus are to select it by tabbing, or by clicking it (focus is applied after the click).

The focus pseudo-class is the most important in terms of accessibility, since it affects users navigating the site with a keyboard or other non-pointing device. At minimum I'd recommend that you apply your :hover styling to the link, whilst allowing any browser-specific styles such as outlines to also apply. Ideally the focus state should be slightly more emphasised than :hover, since it should be easily scannable on a page of content. An added outline is the default in most browsers, and I'd recommend this as an additional emphasis in your own CSS.

:active

The active pseudo-class target an element whilst it is being activated by the user. In practice this is the time during which a keyboard, mouse button, or touch input is between the relevant down and up states (e.g. keydown and keyup).

In modern web-design, the active state should be considered especially useful for mobile users, as it gives a clear indication when an element is tapped that the input has been registered. It is also important for desktop users, for the same reason.

Users have a certain expectation of how links should work based on how they work on other people's sites, and you should match it as much as possible to increase the predictability and accessibility of your website. There are also WCAG guidelines to point you in the right direction.

In general links should have well defined and tested behaviour for all states except visited, since the utility of this state is situational. For any given link, you should be able to;

  • Access it with a mouse
  • Access it with a keyboard
  • Have an obvious state change for mouse interaction
  • Have an obvious state change for keyboard interaction
  • Have a state change which doesn't reflow surrounding content
    • e.g. making an inline text link bold on state change is bad practice, as it alters its size
  • Have sufficient contrast in colour changes
  • Have colour changes accessible for colorblind users

You can optionally have;

  • An accompanying physical change for interaction such as underline or outline
  • A visited state style

Tabindex

Links that should be activated by the user should have a tabindex value. As per the W3 specifications, the following elements have an implicit tabindex of 0;

  • a with href
  • link with href
  • button
  • input where type is not hidden
  • select
  • textarea
  • menuitem
  • elements with a draggable attribute
  • editing hosts (e.g. content editable elements)
  • browsing context containers (e.g. window)
  • Sorting interface th elements

For all other elements you can set a tabindex in one of three states. A tabindex of zero will set the element's tabindex focus flag, and will make it focusable in the DOM order of the document. A negative tabindex will enable the tabindex focus flag on an element, but will not make it focusable using the tab key. This is useful for elements where you wish to set programmatic focus—the most common being for skip links. A positive tabindex will set the tabindex focus flag for the element and place it in the tab order before elements with a lower index, regardless of DOM position (subject to the conditions in the spec).

The main use of a negative tabindex is for features like skip-to-content links. It can also be useful to programmatically control the tabindex of default elements—the Slick slideshow library uses this to prevent carousel items that are off of the screen from being focusable. I've never come across a use for a positive tabindex, and the BBC's accessibility guidelines and the Paciello Group explicitly recommend avoiding them.

tabindex should be set so that elements can be accessed in an intelligent order with the keyboard. In the past this has been achieved with negative margins, but would now be better implemented with Flexbox ordering (or simply constructing your HTML in a logical order).

Skip-to-content

Skip-to-content links should allow users to jump past unnecessary links (such as main menus) and focus directly on the main page content. The intended behaviour is that;

Activating the link sets focus beyond the other content to the main content.

A common issue I've seen with skip-to-content links is that the intended behaviour isn't understood, so the link is implemented with an anchor that skips down the page but doesn't accurately shift the focus;

<a href="#content">Skip to content</a>

<main id="content"></main>

As we've learnt, the reason this doesn't shift focus is because the main element isn't in the focus order by default. You can overcome this by setting a negative tabindex on the content element;

<a href="#content">Skip to content</a>

<main id="content" tabindex="-1"></main>

The negative tabindex makes the element programmatically focusable, and appropriately shifts the focus when explicitly targeted by the skip-to-content link. However, since it's a negative tabindex it's not placed in the focus navigation order, and will not appear in normal navigation. The name attribute should no longer be used for this in HTML5 as it is deprecated—always use an id.

Use of target attribute

The use of the target attribute in links is, and will continue to be, a subjective topic. I'll try to stick to the facts here, but with a little of my own opinion.

Section 3.2 of the WCAG guidelines specify that, for AAA compliance, users should not encounter unpredictable context switches, and should be able to disable them if needed. Applying target="_blank" to a link will force it to open in a new window or tab depending on your browser. For many users this can be confusing behaviour, as it changes their browsing context and breaks the behaviour of the back button. This is an additional impediment for users who rely on screen readers, as it places the onus on the software to declare the behaviour.

The target attribute was briefly deprecated, but has since been reinstated. I don't think this is a bad thing, as it standardises the behaviour to a single attribute (which browsing software can then detect). The W3 recommendations point to both the use of target="_blank" and custom JavaScript solutions (with an option to disable them if necessary). I'd argue that for all implementations you should first be absolutely sure that it's necessary to cause a link to open a new window, and then implement it in a standard way using target="_blank". If you do cause a link to open in a new window, it should be evident from either the link text or styling that this will be the case before the link is clicked.

I believe there are some cases where it is appropriate to use target="blank", and that is where it will improve the usability of the current browsing context. Two examples of where this is used well are Google Docs and Gmail—in both cases taking you to a new page would disturb your current activity, and make it harder to return to what you were doing. Opening the link in a new window or tab is more considerate of the user's needs.

There is a trend of opening links to external sites in new windows when they wouldn't offer links back. The solution here is to make sure you can find your way back, indicate visually the link goes to a different site, or not break the back button, e.g. shopping carts.

Block-level links were introduced in HTML5 in response to the need for making a more complex element than a text string into a hyperlink. Consider a common website feature—a rich teaser containing an image, title, and descriptive text. Without block-level links, your choices are to either to link multiple elements to the content (annoying when using a keyboard), have a single link which is progressively enhanced with JavaScript to make the block clickable (which doesn't work well with common actions like middle- or right-clicking to open in a new tab), or using CSS trickery to make a link fill the whole area.

Block links make this much simpler to implement in a standard way by wrapping all of the child elements in the anchor tag. There are still some styling caveats, but nothing insurmountable. Whilst they are a useful tool, we should be careful, as developers, to use them responsibly.

Behaviour between screen readers varies according to my research—some will announce all elements within the link as separate items, and some will combine them into a single item. In any case, minimising the content inside the link is key—you don't want to bombard the user with large amounts of content.

With the latest version of Voiceover (at the time of writing), the current behaviour is to read all content in the block. For a basic block link like;

<a href="//example.com">
  <img src="//example.com/images/foo.png" alt="A foo" />
  <h3>The eating habits of the foo</h3>

  <p>The foo is a reclusive creature, with some unusual eating habits.</p>
</a>

The announced text is;

A foo. The eating habits of the foo. The foo is a reclusive creature, with some unusual eating habits.

This is fine for this short example, but for multiple links with longer content you're quickly increasing the time taken to navigate the page. If you're going to use block links for major parts of your navigation, be considerate with the length of your content.

As with anything, there are alternative solutions. The Guardian's homepage blocks straddle the line between block and inline links, using an absolutely positioned anchor block which is overlaid by inline sub-links using z-index. Another potential solution is to use this for progressive enhancement, replicating the link behaviour with JavaScript to make the entire element clickable.

Accessibility

When styling your links you should also cater to users who may not be interacting with the page as you might expect. This includes, but is not limited to colorblindness or visual impairment, keyboards or screen readers, touch-only devices, non-JavaScript browsers, and non-CSS browsers.

Color

Colors should have sufficient contrast with the background to be legible in low light conditions, and to users with colorblindness or other visual impairments. Any state changes should likewise have sufficient contrast to be discernible from the previous state. You can check the contrast of your links with the WAVE accessibility tool.

Touch-only devices

As mentioned above, current best practice recommends not using the hover state to present extra information to users due to the difficulty activating it on touch devices. As such, care should be taken that all links are equally usable without a hover state, and that appropriate styling is provided for the active state to give the user a visual clue when they activate a link.

Non-JavaScript browsers

When providing functionality that uses JavaScript, any fallbacks should ensure that the links have a valid href attribute. A common example of this would be an AJAX pager—pager links should link to a valid URL so that if JavaScript is not enabled the user is still sent to a valid location. As such, it is generally not advisable to use links without an href attribute or with href=”#” unless you can guarantee the user will not see them when JavaScript is disabled.

Non-CSS browsers

Whilst uncommon, it’s possible that some users may browse your site without CSS, or with their own stylesheets. As such, it’s important to ensure that your link markup is always semantic, and doesn’t rely on CSS to be usable.

Link text is a simple consideration to making your links more accessible. It's long been advised to not create links with uninformative text like 'Read more' or 'Click here', as this doesn't make sense in isolation. To make these links more accessible, you can include screen-reader only text using a variety of techniques including CSS tricks and ARIA attributes, so you might have a markup of the form;

<a class="hidden" href="//example.com">Read more about foo bar</a>

.hidden {
  position: absolute;
  clip: rect(1px 1px 1px 1px); /* for Internet Explorer */
  clip: rect(1px, 1px, 1px, 1px);
  padding: 0;
  border: 0;
  height: 1px;
  width: 1px;
  overflow: hidden;
}

A better method is to make the link content useful by default—if you're building a CMS, let editors control the link content for calls to action. Or even remove the need for separate calls to action, and make the whole element a link.

Creating a page with a well thought-out link structure and style makes it more usable for everyone. Links are easier to consume in low light, on an old monitor, with poor vision, with a screen-reader, or anything in between. They're more immediately identifiable to a user in a hurry, saving desktop users from scrubbing around with a mouse and tablet users from prodding every corner of the screen to elicit a response. The next time you're designing or theming a web-page, take a step back and consider if that link is going to work well for all of your users—not just some of them.