An accessible design is only the first step in creating an accessible website – you also need to implement that design with accessibility in mind. Here’s how to build your front-end so that everyone can interact with your content.
The visual design of a page is what tells a sighted user whether a big red block on the side of a web page is a button to be clicked, or a container for some navigation.
Users who are blind or partially-sighted will need to be able to make that distinction too, often using assistive technologies that communicate the information onscreen in some other way, e.g. screen readers that read the text and navigation options aloud.
Browsers provide the tools to translate the HTML and CSS of your design not only into pixels on the screen, but also into an accessibility tree. This tree then makes its way through the operating system to the various devices or softwares that can be used to interact with a computer.
Those assistive technologies only know how to process the content because of what the tree tells them. Paying attention to what ends up in the tree – and testing your product with assistive devices – ensures a positive experience for all your users.
Here I’ll detail the basics of implementing your design accessibly, with a focus on:
- using proper semantics to convey information to assistive technologies
- controlling what can be seen and interacted with, and what cannot
Good markup goes a long way
You will need to assign each element in an accessibility tree with a role to let the person know what kind of content they’re dealing with. Is it a link to be clicked or an input to be filled…? It’s likely a page will contain multiple elements with the same role.
Elements also need a label to identify them to the user. And some elements might also need a state (whether a checkbox is checked, for example) and/or a value (for example, which option is selected in a combo box).
‘Paying attention to using the right elements and accurate labelling will set your website’s accessibility on good foundations.’
It might sound like a lot of extra information to put in the markup. Fortunately, HTML elements provide this information out of the box. The first step to an accessible implementation is to use the appropriate elements and not only
<span> styled nicely:
<a>will mark elements users can focus and interact with
- sectioning elements (
<nav>…) will provide landmarks for users to quickly navigate through the page
- screen readers will also provide shortcuts to tables, lists, headings (
Labelling requires a bit more attention. A lot of elements will get their labels from the content they’re wrapping. For example, the label of a button will be the text inside it. Other elements do require a little extra work:
<img>will need an
altattribute to describe the image (or left empty if the image is decorative or the content is right after the image)
- form controls will need to be linked to a
labelelement through its
<fieldset>to have a
<table>will want a
- it’s also a good idea to label landmarks to make them recognisable – you can use the
aria-labelledby(as well as on any other elements, actually).
Paying attention to using the right elements and accurate labelling will set your website’s accessibility on good foundations.
CSS impacts accessibility too
CSS also has its role to play when it comes to the accessibility of a site: with CSS you can ensure your colours are contrasted, font sizes are legible and interactive elements are large enough. Making the the site responsive so users can zoom in is another basic thing you can do.
CSS is also key when it comes to controlling the visibility of the page content. Not just the visibility of the pixels onscreen, but also what gets conveyed (or not) to the assistive technologies.
‘Removing the focus outright is a big no-no. This is the equivalent of removing the pointer for sighted people using a mouse.’
display: none will make elements disappear from the accessibility tree, just as it does onscreen. But it doesn’t let transitions happen, unfortunately. While hiding an element with
opacity: 0 (or translating it off-screen or scaling it to nothing) will remove it from the screen as intended, this won’t make it the element disappear for assistive technologies. You’ll need to use
visibility: hidden (which can conveniently be used for a CSS transition) to ensure it’s not presented to any user.
Sometimes though, you want to show extra content only to the people using assistive tech. There’s a good use case for repeating ‘Read more’ links or ‘Add to basket’ buttons across a page. Sighted users may be able to infer what to read more about or buy from the neighbouring elements. Assistive technology users may not have this context, and may need the label of the element to convey the information.
CSS allows us to make elements disappear from screen but remain present in the accessibility tree using something like HTML Boilerplate’s
.visuallyhidden class. This allows us to add extra helpful content when necessary.
aria-labelledby are also good options for that.
For the opposite (showing things onscreen but not to assistive technologies), you’ll have to turn back to markup and use either
role="presentation" or the
CSS also lets you cover elements with an overlay that will prevent clicks from going through (for example, while loading new content). Just like
opacity: 0 still leaves elements accessible to assistive technologies, using only an overlay lets the elements be reached by tabbing through the page with the keyboard. Unfortunately, CSS doesn’t provide a solution for this one, so you’ll need to update the markup and disable the elements under the overlay one by one, or maybe use the
inert property (with a JS polyfill) to bulk disable them.
CSS also gives you control over how elements appear when focused, letting the user know where they’re on the page when navigating using a keyboard. Browsers provide a default style for it (varying from one to another). While it’s tempting to remove it with
outline: none, just removing it outright is a big no-no. This is the equivalent of removing the pointer for sighted people using a mouse. You’ll want to provide a replacement of some sort to make sure all users know where they are on the page.
Lastly, CSS media queries provide ways to adapt the content to user settings or preferences:
- adjustments for Windows High Contrast mode can be made with the
-ms-high-contrast: activemedia feature
- initiated by Safari, the
prefers-reduced-motion: reducemedia query helps disable animations for users that need to avoid flashing graphics
prefers-color-scheme: darklets you provide a darker colour scheme.
‘If the user has focused on an element that’s getting replaced, you’ll need to re-set which element the focus is on so they can continue their navigation without getting lost.’
focus() method, letting you set the focus on any focusable element on the page (provided its tag is focusable by default or it has a
aria-busyattribute will indicate that the content of an element is being worked on and possibly replaced
- elements marked with
aria-live="polite"will get their content re-read by assistive technologies when updated, allowing notification to get through as changes happen (well, after any current rendering from the assistive technology has happened).
Of course, one aspect we haven’t covered is testing, but I’ll be addressing this in my next post, so be sure to check back here again.
Want to roughly gauge how your build would work with assistive technologies? Try:
- tabbing through the page as you go to make sure interactive elements can be reached and that the focus indicator doesn’t disappear ‘magically’ or appear on things it’s not intended to
- installing a screen reader on your machine to experience how your page renders through it (VoiceOver comes installed on MacOS, NVDA is a widely used free option for Windows, most Linux users rely on Orca).
There’s plenty more to explore when it comes to implementing accessible front-end, but hopefully these simple starting points will allow you to improve the accessibility of your web pages right away.
Ready for more accessibility tips? Try: