Accessibility Best Practices for HTML & CSS
Great accessibility is not always an easy task and goes much more in depth than what is listed here. I still recommend having experienced screen readers and accessibility experts test your site and run your site through the WebAIM Web Accessibility Evaluation Tool, WAVE. If you see anything that should be added, updated, or removed, please get in touch with me either in the comments or @brittneypostma on Twitter. This article is here to serve as a starting point to summarize and guide your way to better accessibility. Having better accessibility isn't only the right thing to do, it also increases your Search Engine Optimization, SEO, which can rank you higher in Google's algorithm. Here are some links to provide more information on web accessibility.
Additional Links
- Introduction to Web Accessibility
- WCAG Quick Reference
- Easy Checks for Web Accessibility
- MDN A good basis for accessibility
Foundation
Everything should start with a good foundation and with Hypertext Markup Language, HTML, that is the structure of your page. A huge part of web accessibility is just making sure the HTML elements are used correctly. A web page may be styled in many different ways to organize information visually, especially with different viewport sizes, but a blind user only hears the order defined in the HTML of a page. In my opinion, using semantic HTML along with mobile-first design allows you to see the layout of a page linearized into one column and the order of the markup to see if it makes sense.
Semantic HTML
The word semantic relates to the meaning of something in a language or logic. In semantic HTML the HTML element used gives meaning to define its content and how it is classified. There are currently over one hundred different elements in HTML, but not all of them have a semantic meaning. The layout of the page defines the page regions that are identified by web browsers and assistive technologies.
Structural
- Use the
header
andfooter
elements to define the top and bottom of a page, but also can define the top and bottom of an article or section. - Use the
nav
element for major blocks of links to allow assistive technologies to quickly and easily navigate through the site. Thenav
element can be used around unordered lists,ul
, or around a block of content referring to multiple links. You can use thearia-label
property to identify different navigation areas. - Use the
main
tag to define the main content of the page andaside
to define anything related to the main content. - Only use
div
s andspan
s for styling purposes. Use thesection
tag to group related elements with a heading and thearticle
tag to group a self-contained item that is independent or reusable. Thearticle
element can be posts, news articles, product cards, comments, or any other form of independent items or content. Here is a great Smashing Magazine article on Why You Should Choose HTML5 article Over section explaining thatarticle
can be used in almost all instances, but asection
with an aria-label can be helpful.
Content
- Use the correct levels for headings, from the most important as an
h1
down throughh6
and do not skip heading levels. Each page should have a heading level 1,h1
, that represents the most important idea on the page. Any sub-headings should be anh2
, sub-sections can then be divided intoh3
s and on down toh6
s based on the nested structure. - Use the paragraph,
p
, element to wrap self-contained blocks of text that focus on a single topic or theme. Also, thestrong
and emphasized,em
, elements have semantic meaning where bold,b
, and italic,i
, are simply style differences. - Use an
alt
attribute on images if the image is important to the content, such as information to understanding or interacting with something. Otherwise, if an image is decorative and adds no value to the content, the attribute can be declaredalt=""
and it will not be read by assistive technologies. - Try to provide alternative to audio and video content, such as captions or transcripts for those that are hard of hearing or using screen readers.
- Use the anchor,
a
, tag for links that go somewhere else and thebutton
tag for an action like submitting a form or a click event.
Language
- Don't use dashes if you can avoid it. Instead of writing 5–7, write 5 to 7.
- Expand abbreviations — instead of writing Jan, write January.
- Expand acronyms, at least once or twice. Instead of writing HTML in the first instance, write Hypertext Markup Language.
Forms
- Forms are one of the most common problems for accessibility on sites. Make sure not to disable any of the default keyboard functionalities or tab order and use the proper markup. Also, consider keeping forms short and only ask users for the minimal information needed to complete the process. https://www.w3.org/WAI/tutorials/forms/
- Use the
label
element with afor
attribute that matches anid
attribute on the accompanyinginput
or wrap thelabel
around theinput
. https://www.w3.org/WAI/tutorials/forms/labels/ - Make sure instructions needed to complete an input are listed before the input area and make clear if an input is required and any validation requirements. Make any errors that prevent completing a form known to the user.
Styling
Styling, whether with CSS or JavaScript, can cause accessibility issues to occur when some browser defaults are removed or incorrectly changed. Including heading and text sizes, outline styling, color contrast, and more. The best practice is to leave the browser defaults if you don't know how to correctly restyle them. I've listed some of the most common issues below. https://developer.mozilla.org/en-US/docs/Learn/Accessibility/CSS_and_JavaScript
Contrast
- There should be sufficient contrast between any foreground text and the background color behind it. The minimum contrast ratio for normal sized text is 4:5:1 and 3:1 for larger text. These are AA minimum contrast criteria.
- There are enhanced AAA criteria at 7:1 for regular text and 4:5:1 for larger text. There are many extensions and plugins that check for contrast issues, but they can be inaccurate and inconsistent. The WebAIM provides a contrast checker at https://webaim.org/resources/contrastchecker/.
- For non-text items the contrast ratio should be a minimum of 3:1.
States
- The focus state shows when a user is focused, either by click, keyboard, or voice, on an element. Only interactive elements need to have a focus state. A common practice is to remove the default outline for focus states with CSS, never do this without replacing it. A background should be 3:1 contrast ratio for buttons and inputs and a minimum 1.4.3 underline for links. More information and examples are listed here https://www.w3.org/WAI/WCAG21/Understanding/non-text-contrast.html.
- The hover and active states are sometimes styled similarly. The active state shows when something is activated, usually a button or a link, and the hover shows when it is being hovered on. The styles are not the important part for accessibility on these elements, but telling assistive technologies when an element is active is important. Using the correct aria-pressed attribute based on the state will tell a user whether the element is active or not. More info on states can be found here https://www.w3.org/WAI/tutorials/menus/styling/#hover-and-focus-states.
Animations
- Users should be able to control any moving, flashing, or blinking content on a page. Examples include ads, videos, auto-updating visuals, moving backgrounds, and more. Basically, anything that is initiated by the page without the user interacting with it. A good practice is to use a prefers-reduced-motion media feature to turn off animations. If the animation is critical to understanding something, add it back in with a selector after turning down all animations. https://css-tricks.com/revisiting-prefers-reduced-motion-the-reduced-motion-media-query/
@media screen and
(prefers-reduced-motion: reduce),
(update: slow) {
* {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important; /* Hat tip Nick/cssremedy (https://css-tricks.com/revisiting-prefers-reduced-motion-the-reduced-motion-media-query/#comment-1700170) */
transition-duration: 0.001ms !important;
}
}
- Make sure all animated content has pause, stop and hide capabilities and check the tab order to ensure it works correctly. The Dark Side of the Grid is a good post on how changing visual order can mess with the order in the Document Object Model, DOM. The Accessible Web Animation Explained post from CSS Tricks has some good tips as well.
- Do NOT have anything that flashes more than three times in a one second period as this is known to cause seizures. If you can't avoid flashing animations, see the W3C's detailed guide on how to meet the safe thresholds.
By no means is this the be all, end all of things that should be done for accessibility. It is an ongoing, ever-evolving process that is an extremely important aspect for inclusion and usability. These are some of the core fundamentals of good User Experience, UX, and helping others understand, navigate, and interact with your site. At a bare minimum, follow these best practices and run your site through the WebAIM Web Accessibility Evaluation Tool, WAVE. If you see anything that should be added, updated, or removed, please get in touch with me either in the comments or @brittneypostma on Twitter.
Top comments (4)
Read this article earlier, didn't have time to comment and say it was really thorough then though! Loved it!
One quick one (sorry, it is my thing to find accessibility errors! 🤣) but as your cover image isn't actually a cover image it could do with some alt text (or changing to a cover image as at least that is a known issue on DEV that you can't add alt text to cover images).
You already have a ❤ and a 🦄 from me, sadly can't add more than one of each!
Awesome, thank you so much. I agree with the cover image. I should add some alt text and the reason I don't use it as a cover image is they don't transform it to the right resolution when it's shared. I had another post that I did their resolution for the cover and it was stretched and cut off on Twitter.
Yeah cover images are strange on DEV, I haven't understood the logic behind making them a fixed height as they don't align with anything, other than perhaps to avoid layout shifts and CLS?
Updated the alt text, thanks for pointing that out