The low-hanging fruit of accessibility

Zenobia Gawlikowska
EcoVadis Engineering
7 min readDec 17, 2022

Retrofitting accessibility to an existing codebase can sometimes seem like a daunting task. The sheer number of criteria to be taken into account might make it seem overwhelming. There are, however, some areas in which accessibility can be introduced at low cost and still provide tremendous benefit to the users.

Photo by Maja Petric on Unsplash

When considering available options, we will consider the highest possible impact in terms of the Web Content Accessibility Guidelines (WCAG) 2.1¹, as well as the workload necessary to implement the desired changes. First, let’s look at the various WCAG levels and what they could mean for us:

  • Level A: must have — when not met, there is no way a user with disabilities can use the application
  • Level AA: if this is met, the user can adjust the settings so they can use the application comfortably; it’s a current industry standard to aim for
  • Level AAA: meeting more strict criteria, including those addressing rare health conditions

In order to be relevant, our effort should aim for the AA compliance level when possible, but the A level should be covered first. Now let’s examine which success criteria in the A and AA range could be taken into account. Here are a few which we have selected:

  • 1.3.1: Info and Relationships (Level A)²
  • 2.4.1: Bypass Blocks (Level A)³
  • 2.4.7: Focus Visible (Level AA)⁴
  • 4.1.2: Name, Role, Value (Level A)⁵

Landmarks

Let’s start with landmarks. Landmarks, or regions with specific predetermined roles, can be very useful to get a quick overview of the available sections on a page. A user who cannot gather this information by visually scanning the layout or who is experiencing difficulty due to cognitive disabilities will benefit from this. Landmarks go a long way towards satisfying the 1.3.1: Info and Relationships WCAG criterion.

From a programmatic point of view, landmark regions are just HTML blocks with implicit ARIA roles assigned to them⁶. Adding them could be as simple as using any of the following HTML tags in the page template:

However, due to compatibility reasons⁷ it might be preferable to spell out the corresponding aria-roles:

UX designers should determine which regions should constitute landmarks. This can be done by way of annotating Figma designs. Useful toolkits are available for this purpose, such as Intopia’s accessibility annotation kit⁸.

Part of Intopia’s accessibility annotation kit

Handy tools for visualizing the implemented landmarks include browser plugins, such as the Accessibility Insights for Web⁹. Screenreader users will be able to navigate landmarks efficiently using shortcut key combinations specific to their screenreader, be it NVDA¹⁰, Narrator¹¹ or JAWS¹².

Headings

Headings are used to communicate the organization of content. Web browsers, plug-ins, and assistive technologies leverage them to provide in-page navigation. It is an important part of satisfying the 1.3.1: Info and Relationships WCAG criterion. Headings allow to skim content quickly both visually and by using shortcuts available in various screenreaders. Headings can have different levels (H1, H2, H3, … up to H6) that represent the page content hierarchy.

Note: it should not be assumed that headings of a particular level are tied to a particular font-size or style.

The meaning of heading levels is as follows: the top H1 level describes the page contents, headings with an equal or higher rank start a new section, headings with a lower rank start new subsections. Skipping heading ranks can be confusing and should be avoided where possible. The order of heading levels should never be reversed¹³.

It may seem easy to follow the heading order but, very often, when developing common components, it might be difficult or impossible to know what heading level should be used. For example, if H2 is chosen, it might end up nested in a section that had a higher level heading, H3. This would cause accessibility validation to fail.

In order to avoid this issue, it is possible to use a library called react-accessible-headings¹⁴. This library helps to automatically determine the appropriate heading that should be rendered in a given context. For example, this code will automatically produce the heading in the current level (the default is H1):

A component that is meant to be nested inside other components (so, anything that is not the main H1 heading) should have the following structure:

The code above will render as H2 if it is located in the top level, or as H3 if it is inside a section that was already defined by a H2 heading, or as H4 if it is inside a section already defined by a H3 heading, etc…

This approach makes it easy to re-use components in various contexts and hierarchies, while always preserving a logical heading sequence. That is very important for accessibility.

Bypassing blocks

The ability to quickly skip blocks of content when using the keyboard is essential for users who rely on using the TAB key for navigation. This could be keyboard power-users, as well as screenreader users. Having to tab through dozens of tab stops just to get to the main content is impractical and tedious. Therefore a solution must be found to this problem and it is quite an easy one to implement. It’s called a skip-link. A skip-link is just a button or link that leads to an anchor located on main section of the page. It is not visible on the page until it is focused on using the TAB key. It is one way of fulfilling the 2.4.1: Bypass Blocks WCAG success criterion.

A skip-link can be created with just a bit of code:

The style for it could be provided in CSS Modules¹⁵ in this SCSS format:

Thus, the skip link button would animate in only when focused, and would otherwise remain invisible. The focus function could be implemented in quite a straightforward way:

The actual main content would be defined this way:

Note: the negative tabIndex is needed to make the element focusable programatically.

Visible focus

WCAG criterion 2.4.7: Focus Visible requires that the focus, you guessed it, remains visible. It is critical for sighted keyboard users, who use focus styles to determine where the current keyboard focus is located. Unfortunately, too often it has been standard practice to remove focus outlines using this infamous piece of code:

This approach has been made popular in 2008 with the reset CSS stylesheets that were used to level the playing field between the browsers, in order to eliminate browser styling that made the behavior of authored styles less predictable across browsers¹⁶. Often CSS authors and UI designers did not provide their own custom styling to outlines, which rendered their websites inaccessible¹⁷.

The solution to this problem is as easy as removing the outline: none; or outline: 0; rule.

Using the built-in browser outline style ensures that the appropriate contrast is determined by the browser. Some tweaks, however, might be needed in order to account for floating labels or any other UI elements which might be positioned relative to the input that is receiving focus. Consider this visual bug, encountered when restoring the built-in outline:

The outline is overlapping with the input label

It can be easily solved with this rule:

The outline is no longer overlapping with the label

More sophisticated focus styles can be applied, of course, using box-shadows and other CSS techniques¹⁸.

Text labels for icon buttons

Icons are a very concise and intuitive way of identifying actions performed by buttons. They are very useful when dealing with limited screen real-estate and can be more accessible for people with cognitive disabilities than an equivalent description provided as text. However, not providing an accessible text description is a serious accessibility shortcoming, which results in failing the 4.1.2: Name, Role, Value WCAG criterion. A non-sighted user simply cannot determine the button function without it. The offending code often looks like this:

The solution is as simple as adding an aria-label attribute with the appropriate action description:

Keep in mind that the aria-labels need to be translated, and this is not always done by automatic translation software¹⁹.

Note: this does not solve all accessibility issues with the above code, as it still does not support keyboard event handlers. This is one of the reasons it’s always preferable to use the native <button> HTML element instead.

Conclusion

The few techniques demonstrated above show how easy it is to satisfy some of the accessibility criteria without dramatic changes to your codebase, while at the same time making a huge improvement to the experience of your users.

References

[1] https://www.w3.org/TR/WCAG21/

[2] https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html

[3] https://www.w3.org/WAI/WCAG21/Understanding/bypass-blocks.html

[4] https://www.w3.org/WAI/WCAG21/Understanding/focus-visible.html

[5] https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html

[6] https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/landmark_role

[7] https://www.accessibilityoz.com/2020/02/html5-sectioning-elements-and-screen-readers/

[8] https://www.youtube.com/watch?v=Y35jmpS8lQM

[9] https://chrome.google.com/webstore/detail/accessibility-insights-fo/pbjjkligggfmakdaogkfomddhfmpjeni/related?hl=en

[10] https://accessibleit.disability.illinois.edu/nvda-for-windows-landmarks-and-headings-navigation/

[11] https://support.microsoft.com/en-us/windows/chapter-5-navigation-68941680-3245-6ef5-5012-0674b8b6fc59

[12] https://www.youtube.com/watch?v=9RpKaLS_1TI

[13] https://www.tpgi.com/heading-off-confusion-when-do-headings-fail-wcag/

[14] https://www.npmjs.com/package/react-accessible-headings

[15] https://github.com/css-modules/css-modules

[16] https://meyerweb.com/eric/tools/css/reset/reset200802.css

[17] In fairness, this has been removed in later versions.

[18] https://css-tricks.com/having-a-little-fun-with-custom-focus-styles/

[19] https://adrianroselli.com/2019/11/aria-label-does-not-translate.html

--

--