For a beginner, accessibility can be daunting. With all of the best intentions in the world, the learning curve to developing compliant, fully accessible websites and apps is huge. It’s also hard to find the right advice, because it’s an ever-changing and increasingly crowded landscape.
I’ve written this post to give you some tips on small things that can make a big difference, while hopefully not affecting your development process too much.
Let’s dive in!
Document Structure and Semantics
It probably doesn’t come as much of a surprise that structuring your HTML in an organized, semantic way will make a big difference. Screen readers rely on a well-structured document in order to follow a coherent narrative, so make sure that you’re using the elements that the HTML5 spec provides responsively and effectively.
If you’re unsure about how to markup your work correctly, check out resources such as HTML5 Doctor, Code Academy and of course, CSS-Tricks. You can also check out articles like “Writing HTML with accessibility in mind” and “Semantic Structure” to get you going in the right direction.
Let’s look at three specific things that can help ensure a well-structured and semantic document.
<main>
Element
Use a Single A good example of building a responsible, semantic document structure is only using one <main>
element. This should serve as a signpost for the most important content of the page for your user.
Add an ID to it and offer a skip link in your main <header>
like so:
<header role="banner">
<h1>Your main page title</h1>
<a href="#main-content">Skip to the main content</a>
</header>
<!-- Further down the document -->
<main id="main-content">
<!-- Put your main body of content in here and other really important stuff -->
</main>
This little trick should help your screen reader users out in a big way, because they can go ahead and skip the fancy bits and dive right into your important content. It’s also great for keyboard users for the same reason.
Another nice touch is to add a :focus
style to the skip link that makes it visible. Try pressing your tab key on GitHub.com. Pretty neat, right?
Use Elements Appropriately
So, <button>
elements are a pain in the butt to style right? That doesn’t mean you should attach your JavaScript events to a <div>
or an <a href="#">
though. You see, when you use a <button>
, you get keyboard events for free. You’re also helping screen reader users out because it’ll announce the element correctly. Check out this example:
document.getElementsByTagName('button')[0].addEventListener('click', evt => {
alert('Oh, hey there!');
});
If a user focused on that button and hit the enter key, that event would fire. That makes both yours and the users’ lives a bit easier. Well worth it, right?
See the Pen Button click example by Andy Bell (@hankchizljaw) on CodePen.
Get Your Heading Hierarchy Locked-Down
It’s really common for screen reader users to navigate a page by using the heading structure. That means we should help them out and create a nice hierarchy for them. Let’s take a look at a standard blog post:
<main id="main-content">
<article>
<!-- The page title is up in the main <header> in this instance -->
<h2>My awesome blog post</h2>
<p>Vestibulum id ligula porta felis euismod semper.</p>
<p>Vestibulum id ligula porta felis euismod semper.</p>
<h3>A sub-section of this post</h3>
<p>Vestibulum id ligula porta felis euismod semper.</p>
<h4>A sub-section of the sub-section</h4>
<p>Vestibulum id ligula porta felis euismod semper.</p>
</article>
</main>
With that sample, the user can navigate to the start of “My awesome blog post” and then have the ability to skip to sub-sections and nested sub-sections easily. They can also skip back up. It’s just a nice way of helping them consume the content you’ve produced as easily as possible.
It can be recommended that a page has a single <h1>
element, even though the W3C HTML5 spec says you can have many. I personally agree with the use of a single <h1>
, but you can have many, as long as you follow a nice structure and hierarchy. That’s the key here.
Get Your Color Contrast Right
To be WCAG 2.0 AA compliant, you need to have a contrast ratio of 4.5:1
for normal text. This is your paragraphs, buttons, navigation, etc. You need to go for a ratio of 3:1
for larger text, such as headings. I’d say this should be your minimum as it’s incredibly achievable with tools such as Tota11y, Contrast and the WebAim contrast checker. You can still get plenty of color balance and variation in your design too.
The reason that contrast is so important is because there’s so much variation in environment that you probably don’t even consider, such as bright sunlight and poor quality displays. Add this to a visual impairment or, say, a migraine and you’re potentially causing problems for your users.
Getting the contrast right will have a huge, positive effect across a wide spectrum of your users.
Responsible Text Labels
We’ve all built out a list of items with a non-descriptive, but visually appealing “More” button, right? More what though? We need to be more responsible with this and provide some context.
One way to achieve this is by visually hiding descriptive text with CSS and hiding the non-descriptive text from screen readers. It’s tempting to use display: none;
, but screen readers can ignore elements with that set, so we need to be more creative. I use something like this little helper:
.visually-hidden {
display: block;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px);
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(1px);
white-space: nowrap;
position: absolute;
}
With this CSS in place, we can do something like this:
<a href="/link-to-your-page">
<!-- This is hidden from a screen reader, but visible visually -->
<span aria-hidden="true">More</span>
<!-- This is visible to a screen reader, but visually hidden -->
<span class="visually-hidden">Continue reading: "Your post title here"</span>
</a>
A sighted user will only see “More” and a screen reader user will hear “Continue reading: ‘Your post title here.'” Both sets of users are happy.
You can also achieve the above by using an aria-label
on the <a>
tag. This will override the text within for a screen-reader:
<a href="/link-to-your-page" aria-label="Continue reading: 'Your post title here'">
More
</a>
Small Typography Tweaks With a Big Impact
It’s always worth remembering that people with a visual impairment or learning difficulty could be trying to read your content, so some small tweaks to your typography can go a long way.
A body of content such as an article should be sized at 16px
(or equivalent unit) at a minimum. It’s also worth increasing your line-height
to around 1.5
too. Space between lines can help readers with dyslexia to understand your content better. The combination of size and space is also great for older people and/or short-of-sight people. Even small summaries and aside content should be at least 12px
(or equivalent unit). Anything smaller than that will alienate users who struggle to read.
Another trick is to highlight key words and phrases if your content is quite complex. This not only benefits users who are slightly slower at processing content but it also helps people who like to scan over an article, like I do.
Lastly on this section, I’d advise you to be careful with your font choices. Fonts with complex ligatures and decorative elements can be really distracting, so maybe limit the usage of those to key, large headings only. It’s also been advised that sans-serif fonts are better for readers with dyslexia. Check out this article for more on that and other text formatting tips.
Enhance Keyboard Support
There are a few little tweaks you can do to help users who primarily use their keyboard to navigate your website.
Say you’ve got a little button that shows a dialogue when you click it. You should attach an event to the escape key that hides it. Here’s a sample snippet:
document.addEventListener('keyup', (evt) => {
if(evt.keyCode === 27) {
// Run whatever code hides your dialogue
}
});
See the Pen Escape key demo by Andy Bell (@hankchizljaw) on CodePen.
Another tweak you can do for our keyboard-navigating buddies is not hiding focus from them. Browsers give us focus states for free with outline
. I know it can look ugly, but hot-damn it’s useful for keyboard users. If you want to get rid of that blue glow, I get it—just please use the :focus
pseudo selector to add an obvious state change to it instead. Here’s a sample:
.your-element {
background: red;
}
.your-element:focus {
outline: none; /* Reset the default */
box-shadow: 0 0 0 3px black; /* A very obvious state change */
}
Don’t Rely on Color Alone to Communicate State Changes
Let’s end on a really important one. Color shouldn’t be relied upon alone to communicate state changes. Take this scenario as an example:
You’ve got a button that posts a form. You wrote some neat JavaScript that makes it go grey while it sends the data. It then either turns green or red, depending on what the status is.
For a colorblind user, this is a nightmare. To them, the button may have barely changed enough for them to notice, so they may just keep clicking and clicking while getting really frustrated. This isn’t ideal.
So, instead of relying on color, let’s enhance that with a status message that supports the button’s state on response.
See the Pen Enhanced state change communication demo by Andy Bell (@hankchizljaw) on CodePen.
That sample is a great way to quickly communicate to the user that something has changed and the use of color, text and iconography clearly communicates that change. Disabling the button whilst the response is processed is also a great help to the user.
Wrapping Up
These little tips should make a big difference to your users, and I hope you dive into your projects and implement some of them.
You should also keep learning about accessibility. I recommend following people such as Heydon Pickering, Scott O’Hara, Laura Kalbag, and Rob Dobson on Twitter. I also recommend that you check out resources such as Inclusive Components and the A11y Project.
The greater your knowledge gets, the better your websites and products will be for a much wider audience. That can only be a good thing, right?
Hot damn that was a good article, thanks!
Thanks Brian! I hope it helps you make some awesome accessible websites.
I get using just one main element, but I’m wondering what it means now that in HTML5.2 having multiple main elements on one page is considered valid HTML.
As far as I’m aware, you can only have one
<main>
element visible at any given time. Other<main>
elements should be hidden like so:<main hidden>
. That will hide it from a screen-reader. You could alternatively use CSS and add thearia-hidden="true"
property, as I mentioned above.The
hidden
attribute is a totally valid way of hiding elements visually and from screen-readers, so it’s worth having in your toolbox.Actually WHATWG consider multiple main elements valid (so you can have a header, main, footer in each section). But they might change that in future. There is recent proposal to change that.
BTW, to my knowledge no screen reader supports the main tag. They all skip to first h1 element and h1 should be directly above main content.
CSS property CLIP is deprecated, but you can use CLIP-PATH for new browsers. Anyway, great article :)
Ah, thanks very much Mino. Looks like I’ll have to work out a new way of using
clip-path
in the future. Hopefully the premise of usingclip
will still be useful to folks though .Bootstrap, as much as I despise it, uses .sr-only class for skip navigation link with
Would you say this is OK to do, I mean does the CSS check out like that or can I just use visibility: hidden on the skip-to-main link?
Reference:
https://a11yproject.com/posts/skip-nav-links/
https://v4-alpha.getbootstrap.com/getting-started/accessibility/#skip-navigation
https://github.com/twbs/bootstrap/blob/v4-dev/dist/css/bootstrap.css#L7365
The CSS checks out for sure. The Bootstrap team don’t muck around :)
Pretty neat tweaks indeed. Minor changes, but quite helpful. Thanks.
No worries. I hope it helps you to help others :)
Very good article :) It makes thinking about accessibility a lot easier when you know a few “quick wins” you can put in from the start.
One thing that might be worth adding is being aware of “smushed offscreen text” (https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe) when visibly hiding text. Adding
white-space: nowrap
works wonders.Nice one! I’ll add that to my reading list. Thanks :)
Really good article! Cheers
Thank you :)
I’ve always used a slightly different class for hidden descriptions, evolved over the years:
I believe (but am not totally sure) that clip went through different iterations of syntax hence the comma version of rect, catching a few different vendor implementations before it was phased out. The new clip-path with inset appears to replicate the old clip behaviour correctly and is the preference if you don’t need fallbacks.
Using height and width of 0 can sometimes hide an element in the same way that display:none does, so using a 1px width and height is safer.
The other properties keep the text out of the page flow, with overflow and wrapping behaving themselves.
Ailwyn beat me to it, specifically the declaration of
white-space: nowrap;
. Excluding it can cause screen readers to speak the hidden text letter by letter as it tried to honor the browser’s attempt to wrap the text in the tiny container. More info in Jesse Beach’s article: https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfeThe non-comma clip —
rect(1px 1px 1px 1px)
— targets IE6 and IE7.Cheers for that. It’s a great looking class.
I used to absolute position
.visually-hidden
myself, but had issues with focusable elements, such as checkboxes that were visually hidden when they were offscreen, or within anoverflow: scroll/auto
container.Awesome, cheers Adrian! Some really useful feedback. I’ll update the snippet in this article based on yours and others feedback.
Thank you!
Great article! Regarding text labels, what is the advantage to “aria-label” over plain old “title”?
Basically, there’s a chance that it wont be read by a screen-reader. This article is an old one, but a good one: https://silktide.com/i-thought-title-text-improved-accessibility-i-was-wrong/
A lot of people don’t style focus because they don’t like the fact it applies the style to both keyboard and mouse focus. There is a css style for :focus-ring which allows you to only style focus via keyboard. Currently not widly supported but there is a great polyfill for it!
I think a lot of people don’t style :focus because they’re not aware of the need for it to be different from :hover. I’ve had to argue the difference on more than one occasion myself!
I have a question about header structure. I’ve read that you can have multiple H1 tags, an example would be the home page of a blog. The structure would look like this.
Main
H1
Article
Header
H1
/Header
{content}
/Article
Article
Header
H1
/Header
{content}
/Article
Article
Header
H1
/Header
{content}
/Article
/Main
Is this correct? Also if you have multiple Section tags, can each one have a H1? Or do you need to increment your H tags?
Your heading structure should reflect the content, not the use of
section
,article
, etc. The advice about using all-h1
s (or even multiple) came from the proposed Document Outline Algorithm. However, it was never implemented in any browser and likely will not be. Ideally, oneh1
per page, and it should reflect what the page is about (and correspond to thetitle
element).That being said, I advice authors to not use
section
norarticle
unless it opens with ah#
(whatever level is appropriate). That is because these elements are sectioning elements in HTML and should have accessible names for assistive technology to convey to users. Usingh#
gives you that. Otherwise, you may be using these elements as styling hooks, which is not their purpose.The key is hierarchy. So yes, have many H1s in many sections, but make sure headings within the section follow a hierarchy.
The reason I like one H1 is that it gives you master heading, then the H2s are used to landmark top level sections in a page. But as I said above, it’s totally valid to have many H1s.
Andy, multiple
h1
s is valid, but is often user hostile to those who rely on it most. My own usability testing coupled with general surveys (see the latest WebAIM screen reader user survey at https://webaim.org/projects/screenreadersurvey7/#heading) tell me that the ideal path is a singleh1
.That’s really useful insight, Adrian. Thank you. I’ve always been a bit passive about multiple
h1
s, but I’ll be really pushing the singleh1
approach now, citing that research :).visually-hidden seems so hacky. Is there really no aria attribute to handle this yet in the HTML spec?
Thanks for the article demystifying the accessibility basics. The aria-label example for the “more” button suggests to me a more universal fix: if the “more” text is not clear to users of AT, perhaps it’s not clear to anybody? Good use of the accessibility features of browsers also means knowing when NOT to use them – the web is accessible by default, and presenting a consistent UI to all users is simpler and better.
Why the excessive properties on .visually-hidden? Is there anything wrong with this:
The
.visually-hidden
class is less about excess, and more about flexibility. You can drop it in anywhere and it shouldn’t break your layout, which is what we’re after.ARIA is essentially a separate spec and is supported by screen readers only, so an ARIA attribute would not benefit non-screen-reader users (unless you use them for CSS selectors). An attribute to only visually hide things is the domain of CSS, not HTML. It seems to me that the approach above, though clunky, honors the separation of concerns. If you have a tangible proposal, by all means, please propose it. The W3C is always looking for feedback from more developers, especially if they have ideas based on practical experience.
As a block element, without an explicit width it will still take up space. It may also show scroll bars. It is also insufficient to support back into the IE world. The IE part is important since many folks who rely on assistive technology are stuck with IE due to support from their employer, the vendor, and even policies.
Andy Bell, thanks for your article and for spreading the word :) Just a quick note that building a focus style using only box-shadow is problematic with Windows High Contrast Mode, as it removes any background and box-shadow. The result would be no focus style at all. Outline and border still work.
Thanks for the feedback, Andrea – that’s good to know. I’m learning a lot from this comment thread :)
I’m hoping the takeaway will be more “I need to make sure my focus states are obvious” more than specific CSS props. I’ll be keeping that little nugget of info in my arsenal though.
The example with aria-hidden used inside a link is also a bit controversial. Screen readers may read out that anyway, for example VoiceOver reads “More” when navigating content character by character. Pretty sure other screen readers may read that out too. Also, for voice-controlled assistive technologies *speech recognition software) serving 2 different text (one for visual and the other one for software that understand ARIA) can be problematic and not allow users to access that control, as clearly stated in the ARIA recommendation.
Also good to know. Thanks Andrea :)
Great article !
Just an observation, in section “Don’t Rely on Color Alone to Communicate State Changes” you’re right expect that the state change when hovering the button is too small. Color differences between normal and hover button are too subtle.
For me hovering is a state change :)
Good catch Victor! I’ve given the pens a little tweak :)
A MILLION thumbs up on the
esc
key functionality suggestion. The mouse is such an annoyance with my disability. I always go to that to close pop-ups and inevitably go to notify the site owner if it (or a similar shortcut) doesn’t do the job.I find it incredibly frustrating myself too. I hope this article will create some awareness across the board and you’ll find less examples in the wild, going forward :)
I am a disabled and operate the computer through speech recognition. Many popular websites like Facebook, Pinterest depend on keyboard events in order to execute code in the search box. However, speech recognition software like Dragon NaturallySpeaking does not trigger keyboard or mouse events at times. When someone dictates, they instead trigger Windows Journal event’s on Windows. this is a huge problem on Facebook. I have worked around it by writing custom code in order to emulate keyboard press actions when I dictate. However, it falls flat when I am trying to use some macros.
It would be great if the guidelines for accessibility include watching for the Windows Journal event is also. I hope this is it becomes a part of WCAG guidelines. However, I have yet to see any traction on this.
I hope you can consider the merits of this suggestion and then include this in your recommendation.
It’s so hard as a developer to account for this. I’m so glad you commented though, because I’ve certainly learned something today.
I’d say to developers to use the
input
event for input detection, personally. I wonder if that would help in your scenario, because an event is fired for every character that’s inserted or deleted?I believe the skip to main content should be the first focusable element in the page and not placed inside the
<header>
element and after the<h1>
Page title as shown in the example: