Minimum Efforts Web Accessibility for Developers

Igor Afanasov
Publication Date
15 September 2020

Minimum Efforts Web Accessibility for Developers

In almost all the projects I’ve ever worked on, accessibility was a low priority. Well, in the best cases. Usually, it was not considered at all. Most of my clients were not ready to pay for accessibility. With a little knowledge, developers can make a difference for users. This article will focus on two main areas: helping screen readers and managing focus.

Lots of accessibility aspects depend on design and user experience (UX). Those are out of the scope of this article. Instead, we’re focusing on items relevant to developers.

Key takeaways within developer control:

  • Use semantic markup
  • Consult WAI-ARIA authoring practices
  • Keep the visual order of HTML elements the same as it is in the source code

Understanding screen reader navigation

Let’s not pretend to be screen reader users and just see how they actually use screen readers. The screen recording from Victor Tsaran, Google’s technical program manager, is a good showcase:


That was quite fast, right? We need a bit slower pace to comprehend how the user navigates with the screen reader. With a special key combination the user moves from one element to another. Currently, the active element is highlighted with a border.


It looks similar to focus. In comparison to focus, however, the screen reader navigates through all the page elements. For example, focus navigation with the `tab` key will skip paragraphs, while screen reader navigation will visit it.

Exploring each element one by one is not very productive. Screen reader technology provides several navigation menus to speedup interaction with the page. In mac’s voiceover these menus are provided by rotor. The hotkey to open the rotor is VO+U. A user can change the settings and the list of available menus. Let’s explore the default menus. The English wikipedia home page would be a great candidate for exploring the rotor menus.


Here is the list of the page links. You can see the link text here. And you can probably spot some links that do not have a semantic meaning. Like this big number 6,118,943. Without the context - the text around the link - it is impossible to comprehend. If we consider changing the link text, it could be tricky. The visual appearance is one of the reasons but there could be others as well.


In this case, descriptive text for the link could have been “6,118,943 articles in English.” but it requires nested links because “English” is a link already. Nested links are a bad idea. A more reliable option could have been adding an ARIA attribute to provide the special text for the screen reader. It could be aria-label with text, aria-labelledby or aria-describedby with comma separated IDs of DOM elements, where the content would be used for announcements.


This is the page outline. All the headings are listed in the same order and hierarchy as in the markup. That is a really convenient way to understand the page structure and navigate through it. The good usage of headings in the markup would help screen reader users a lot. It is such a convenient outline, I even installed a browser extension to have the same outline. 

Form controls

Inputs, dropdowns, text areas, and other controls end up here. You might recall it once you implemented controls yourself. WAI-ARIA authoring practices will help you with guidance on what to do to make your control listed here.

Web spots

Web Spot is a gray area. It’s not that easy to find proper documentation about it. Wikipedia doesn’t even use it. Let’s skip this one.


Here are listed HTML elements with specific roles. You might recall the `role` attribute. This is the role I’m speaking about. For most landmark roles there is a HTML element with implied role. Those are `header`, `footer`, `main`, `section`, `nav`, `form`, `aside.` For some HTML elements it is a bit tricky. The `header` element has implied a landmark role only if it’s direct parent is `body.` For others it is straightforward - `section` always has a landmark role implied.

Only one landmark doesn’t have a semantic HTML element. It is the search. Developers need to add a role attribute with value ‘search’ to the ‘form’ tag of the search form.


The Articles menu is the same as web spots - poorly documented and Wikipedia doesn’t care about it. Let’s skip it.

Window spots

It’s operation system level. We as web developers don’t control it.

That was all the default rotor menus. Time to explore what we can do to make the screen reader experience better.

Improving the screen reader experience

Consult the “WAI-ARIA Authoring Practices” document

There is a really good detailed document to help us: WAI-ARIA Authoring Practices document. This document provides guidance on how to use WAI-ARIA to create accessible, rich internet applications. It describes considerations that might not be evident to developers and recommends approaches to make widgets, navigation, and behaviors accessible using WAI-ARIA roles, states, and properties.

If by any chance you decide to implement a widget yourself, you should also consult this document. It will help with guidance for the most popular widget. It includes expected behavior, accessibility considerations, and keyboard interaction. I hope this document will change your mind and you will use the component library instead of reinventing the wheel. Here are five considerations to keep in mind:

1. Use semantic markup

This is probably the most important point. Semantics help the screen reader to build a better experience. The same way that a developer could better understand the semantically meaningful code, the screen reader can also process it better. All semantic HTML elements have implied ARIA attributes applied. For example, these two samples of markup have the same meaning for the screen reader.

While most developers have never thought about it, semantic elements provide a lot of information implied. Based on that information, the screen reader announces the page content and builds navigation.

2. Build a page outline with heading tags (h1, h2, h3, etc.)

Screen readers build a table of contents based on the headings. Proper usage of heading tags provides the user with a great page overview and convenient navigation.

Avoid using heading tags just for styling purposes. Similarly, avoid styling non-headings elements to look like a heading if they are headings.

3. Provide context-independent link text or an alternative

Same as with the headers, screen readers provide the opportunity to search links and navigate to them. The canonical anti-pattern is a link text “read more.” It does not provide any useful information without the context around the link. As an alternative, consider using more descriptive text like “read more about lemurs.” Another option is to add an aria-label or aria-labelledby attribute with text for a screen reader.

The attributes approach also works well for links with visuals. Like the npm link on the ng-bootstrap site (screenshot below). You might see an npm logo next to the downloads count. Screen readers can not describe the SVG content and need the help of ARIA attributes to make a proper announcement.

4. Set the alt attribute for images

For standalone images ‘alt’ should be a short description of the image content. That was the easy part. The rest is a bit tricky.

If an image is placed inside the link, the screen reader announces the link using the image ‘alt’ attribute. Having the description of the image could be quite confusing here. For example, a logo image on the ng-bootstrap site with alt “The B letter on the shield” would make it difficult to understand where this link leads to.

In some cases, it is desirable for some images to not be announced by a screen reader. Consider a navigation link with an icon. Like this link to the search page:

This markup is announced as “magnifying glass search.” That is a bit confusing. Removing the “alt” attribute leads to the announcement of the image file name which is not desirable here. To make things more understandable we can set “alt” to an empty string. The image would not be announced at all. 

5. Set the lang attribute

The lang attribute is a global one. That means it could be used with any HTML element. It’s a good practice to set lang in the top-level “html” element. Any HTML element with a content language different from the top-level language should have it’s own “lang” attribute.

Here is the HTML Language Code Reference to help you find the right language code.


Focus determines where keyboard events go in the page. For users, it is usually nice to visually recognize which element is focused. While designers determine the actual look and feel, developers are ones who apply those styles. One nasty thing waits for us here. A user might expect to have a visual styling of a focused element only if they navigate with keyboard shortcuts. When you click the button or input text you know where the focus is now without a special visual outline. Unfortunately, the browsers are not consistent in this area. For some elements, some browsers add the focus styling on click. There is no known approach to make this behavior consistent. There are just some ad-hoc approaches for specific cases. Be prepared for the pain here if your UX specialist does not accept the default browser behavior.

Let’s explore how as developers we can affect focus experience.

Manage focusable elements

We can leverage the “tabindex” attribute. There are 2 legitimate values:

  • A negative value (usually tabindex="-1") means that the element is not reachable via focusable navigation, but could be focused with Javascript. It's mostly useful to create accessible widgets with JavaScript.
  • tabindex="0" means that the element should be focusable with the keyboard navigation, but its order is defined by its order in the source code.

Any positive number is a code smell. The focus order made with positive tabindex attribute value could be easily broken with refactoring. It’s almost impossible to reuse the widget containing positive tabindex into the page rich with widgets.

That means the best way to keep the order of focusable items is to synchronize the visual order of elements with the source code order. We could desynchronize it accidentally. One common caveat is changing the order with CSS property float. Like in the example below the element with text “One” visually appears on the right while in the source code it is in the first place. Focus will navigate first to this element and only after it will go to the element with text “Two” which is confusing.

Another caveat is fixed or absolute positioning when the element’s position in the DOM does not matter. A sticky footer would be a good example. It’s easy to forget to place it in the logical order since it does not change the visual appearance at all.

The easiest solution to keep the proper focus order is to navigate inside the page with the keyboard once in a while.

Before you leave

My congratulations on becoming better acquainted with web accessibility and the approaches to make the user experience better!

By no means is this article a comprehensive guide. Accessibility is a very broad complex topic. This article employs you just with some knowledge to apply right away as a web-developer. 

If you want to learn more, I highly recommend the free accessibility course from google. It's a nice, practical resource.

Thanks for reading and sharing!



Let our expertise complement yours

Leave your details below and we'll be in touch soon.