Make your site accessible. Step by step instruction

Last Updated On


You can find many articles talking and describing accessibility for the web. Most of them are just discourse or they're aimed to cover specific aspect. There's nothing wrong with that since this is a very wide topic. However, when it comes to "implement accessible website or web-app" or "get the job done" I couldn't find any step-by-step instruction telling me what to do to make this happened. This article is aimed to help you build an accessible website or web-app by providing a list of TODO's. You can read brief intro paragraphs (the story, what is accessibility, etc.) or jump straight to each requirement and start to implement it.

The Story

A while ago, I needed to refactor a website due to an absence of the accessibility. For a lot of developers, term accessibility is a rocket science and I wasn't an exception. It requires a meaningful amount of time to research and understand all ideas around it. It is also really difficult to check whether your implementation is right or not. I faced a lot of issues that are either partially explained or not described at all. I went through the unknown way of specific HTML rules and attributes, trough the heavy battle with UI designers and through the bugs I didn't expect to see. In this article, I would like to share how we can make websites accessible in the easiest way possible by applying a set of HTML laws with a help of CSS and JavaScript. But first of all, let's define what is accessibility from the web perspective.

What is accessibility?

Accessibility is a practice to make sites usable for people with impairment. Most of the time when we use term "impairment" or "disabilities" on the internet we mean blindness. However, there are other types of impairment: visual (not only complete blindness but also color blindness, visual impairment), auditory, physical, cognitive. In this article, most of the time I will use examples for blind people. Nevertheless, I'll also cover accessibility techniques for other types.

Small note: You may also find a term "ADA Compliance" where ADA stands for "Americans with Disabilities Act". In this context, I'll use it with the same meaning as "Accessibility".

How many people are affected?

Research of the October 2017 shows that 283 million people are estimated to be visually impaired worldwide: 36 million are blind and 217 million have moderate to severe vision impairment source. If we will take into account that in 2017 the planet was inhabited by 7.6 billion people, we can calculate that ~3% of all population have the visual impairment. It's a huge number, considering that our population always grows and there would be more people affected by this. In addition to that, this case doesn't highlight the people with other disabilities like auditory, physical, cognitive.

Why do we need to make sites accessible?

  • Satisfy existing, get new clients and increase the audience. Let's assume that you have a product that is being used by a handicapped person. This might be already existing customer or somebody who just started using your software. If you would not create an accessible option, he or she will complain about your product or just find a better alternative that supports assistive technology.
  • Boost user experience. Even if a small part of your audience can't leave home due to their physical abilities, you can make them happier by providing enhanced shopping experience.
  • Benefits for people without disabilities. In some cases, it's way faster and more convenient to navigate through the site by using keyboard only.
  • SEO Improvements and meaningful markup for search engines. Google and other search engines would be happy to see the correct heading structure. An alternative image is extremely useful as it can tell what particular image actually is about.
  • It's the law. In USA, Canada, UK, EU, other unions and countries.
  • Because you simply care.

What are the tools that can help us to make web-site accessible?

The list of more popular tools is available on w3c.

How can I make website accessible (the main accessibility part)

There is a lot of documentation you can find and as I mentioned, it might be really overwhelming. However, I want to keep it simple and want you to understand one important piece. Here it's:

There is a technical standard called WCAG. This standard has three levels of conformance: A, AA and AAA. Yes, it might sound complicated, but in fact, it's really simple and you can think about these levels in that way: the higher level you meet, the more accessible your site becomes.

alt text

As you might guess each level requires different set of features to implement and the higher the level the more difficult it's to do.

Great! Right now you learned one of the most important theory parts. Let's take that and move to the next section where we would take a look at the requirements for each level.

"A" Level of Conformance

In this part, I'll explain what I feel most important and easy to implement requirements. That's also a good starting point since we need to complete A level before diving into other ones.

Every image should have an alt attribute

That's probably the most known requirement. Here is the problem though: not everybody knows what kind of information it should contain and for what purpose it serves. alt attribute provides an alternative text to the image if the person couldn't see it or it's not loaded. From the accessibility point of view it can have two values:

  • Null value (That's what W3C says. But, that is not a regular null value as a separated data type like in Java, PHP or JavaScript. In this context it actually means empty value or alt="").
  • Non-null value, i.e. when it actually contains alternative text, e.g. alt="Jean Sibelius, the work's composer".The question is: when do we need to specify the value and when do we need to leave it empty? The answer: If it's an instructional image you should put an alternative text. If it's a decorative image you can leave attribute empty. In other words, try to remove the image out of the current context. Does the text lose its meaning? If the answer is yes then it's instructional image and you need to provide alt text. Otherwise, it's decorative image and you can leave alt empty.

There is a common mistake regarding instructional image: many editors put image title or description into alt text. That's wrong. You should put the instruction that is provided by the image instead. And again, you can test your alternative text by removing the image and seeing, if your content still has the same sense.

Example of this can be any blog page that has links like "Read More" or "View More". The problem here is all of these links are identical for the person with disabilities. It's really obvious for a non-disabled person, but in some cases, it's impossible to know the difference what are actual articles links are pointing to for a person with an impairment.

Before going into the solution, let me show you a picture that demonstrates that:

 alt text

This page has several articles and each one contains the same "Read More" link. Here I wrote some approaches how we would solve it:

1. Apply different title attribute to each link. For example

<a title="Read More About Today's events" href="yourblog/post3323">Read More</a>
<a title="Read More About Today's Market" href="yourblog/post1523">Read More</a>
<a title="Read More About Politics" href="yourblog/post9253">Read More</a>

W3C - technique 33

2. Rename each link. For example

<a href="yourblog/post3323">Read More About Today's events</a>
<a href="yourblog/post1523">Read More About Today's Market</a>
<a href="yourblog/post9253">Read More About Politics</a>

W3C - technique 91

3. Use aria-label attribute. The technique is identical to title attribute (where you provide extra description without affecting actual view), but by using aria-label instead. title and aria-label attributes wouldn't be shown in the browser except the case when you hover over the link. W3C - technique ARIA8

4. Use aria-labelledby attribute. In this case we need to have an element the link would refer to. This situation will be suitable when you already have a unique description for your link and don't want to be repetitive (and you don't have to). Just assign an id attribute for the post-headline and point a link to it by using aria-labelledby attribute.

<h2 id="post-headline">Events that are happening today</a>
<a href="yourblog/post1523" aria-labelledby="blog-headline">Read More</a> 

W3C - technique 91

Screen reader will announce this as "Read more ... Events that are happening today"

This rule implies that all links should have different color from the surrounded text for users who can't distinguish between colors.

Solution: To meet "A" level of conformance text color of each link should differ from the surrounding text by a contrast ratio of at least 3:1. You can use one of the contrast ratio checkers that I mentioned few sections above or anyone you like.

extra info

Every page should have right heading structure

The idea behind this requirement is a web page should have a right hierarchy of h1 - h6 tags. I guess, if you're reading this article, you probably know this. However, due to styling reasons, some developers put h3 tags without having h2 on the page which goes against this rule. To meet this requirement there're several points you should avoid:

  1. Empty heading tags, e.g. <h2></h2>.
  2. Multiple H1 tags on a page. As we discussed only one H1 per page.
  3. Use headings in random order (most of the time this happens because of the styling reasons). Instead, we should organize them in hierarchical/semantical way, where each tag of the "higher rank" precedes to the tag with the "lower rank".

More examples and info about this requirement on W3C

Emphasise text correctly

This is a simple criteria instruct how to use proper HTML5 tags for text emphasis. In this case <blockquote> tag might be a good example of this usage. We can put <em>, <strong> tags in the same category.

However, in accordance with this rule, we should definitely avoid instances of <i>, <b> tags on the page. These tags were used in HTML 4.01 to render text in italics/bold. This is not a case for HTML5 anymore.

In addition to that, a lot of icon fonts (like fontawesome) use <i> tag. Even though "fontawesome" suggests you to add aria-hidden="true" attribute, there're might be other alternatives. Like this for example.


Be sure for having unique id across the page

This requirement speaks for itself. Most of the time when you manually create HTML this doesn't happen. However, many coders forget about it when they generate HTML elements or components through the for loop. An example might be a blog page with a couple post previews on it. Each of this post would have different visual content(image, title, subtitle), but in HTML structure it might have the same id. Just pay attention to that.


Get rid of the presentational attributes if you have ones

This one less likely applicable for modern web. However, if you found presentational attributes such as bgcolor, width, border, height, etc refactor them with proper CSS styles. In our days you may face them in iframes or old markup. Just to make sure that we're on the same page, here's piece of HTML with presentational attributes:

<iframe width="560" height="315" src="" frameborder="0" gesture="media" allow="encrypted-media" allowfullscreen></iframe>

Here width="560, height="315" and frameborder="0" are presentational attributes.

Refactored version

<iframe class="demo-youtube" src="" gesture="media" allow="encrypted-media" allowfullscreen></iframe>
h1 {
    width: 560px;
    height: 315px;
    border: none;

The full list of presentational attributes can be found on whatwg.

Always set language of the html tag

Pretty easy, but still worth to mention as it is a part of "A" level. The best way to explain lang attribute is by example:

<html lang="it"><!--this is lang="it" attribute-->
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
<body> pagina in italiano...   


Set descriptive title attribute to an iFrame

The idea is identical to the distinguishable links point, but in this case, it relates to iframes. Basically, when a person lands on the page and hears a list of iframes, it's very useful to know the content of each one. That's where title attribute can help (yes, the same attribute like we used in links). Example:

<iframe src="" class="demo-youtube" gesture="media" allow="encrypted-media" title="4k demo video about nature" allowfullscreen></iframe>

More details

Always use labels to describe purpose of the input, textarea or select element

As I found, most code editors or IDEs (in my case it's IDEA based WebStorm/PHPStorm) notifies me when I forget about that rule. It tells that each form control on the page have to be associated with a label. Example:

<label for="email">Email</label> 
<input type="email" name="email" id="email" />


<input type="email" name="email" id="email" />
<label for="email">Email</label> 


    <input type="email" name="email" id="email" />

Either one of those variations is correct. The same logic applies to textarea and select.

There're few exceptions though. Labels shouldn't be used for the following cases:

  1. Submit and Reset buttons (input type="submit" or input type="reset")
  2. Hidden input fields (input type="hidden")
  3. Script buttons (button elements or <input type="button">)

These "form controls" already explicitly declared their behavior through their type attribute.


Expose WAI-ARIA attributes (Theory part)

Before going to overwhelm you with another bunch of terms I want to go briefly through another theory part. Let's talk about WAI-AREA a little bit. WAI-AREA (Web Accessibility Initiative – Accessible Rich Internet Applications) or just ARIA is a technical specification published by the W3C that helps increase accessibility of the sites and web-apps. Basically, it's a set of the HTML attributes that can be applied to the elements to provide semantic meaning.

There are three main categories of the attributes defined in the ARIA spec:

  • Role - attributes belonging to this category provide semantic meaning what element is or does. That’s where we will see “role” attribute in action. You probably already faced with some of the examples like <header role=“banner”>, <form role=“search”>, <footer role=“contentinfo”> and others. These roles also so-called landmarks (navigational landmarks or landmark roles).

  • Properties - attributes belonging to this category provide extra meaning or semantics. The very basic example, in this case, will be <input aria-required=“true”> that shows that input is required.

  • State - attributes belonging to this category define a state of the element. For example aria-disabled=“true”, which says that a form input is currently disabled.

You can find all roles, properties and states on W3C.

Another question you may ask: why do we need extra ARIA attributes? After all, we have standard HTML attributes like “required”, “disabled” or HTML5 tag “nav” that says that “nav” is navigation.

The answer is that ARIA attributes are read by assistive technologies. ARIA helps to build “accessible” version of the web page that will be used by screen-readers to reproduce the information. In addition to that, state attributes and properties help handle dynamic page changes (such as disabled-enabled buttons and form fields) which might not be obvious for "helper software" in some cases.

To give you an idea, what actually happens behind the scenes: in addition to the DOM tree, browsers also expose Accessibility tree (through the internal API) that is used by screen readers. Actually, Accessibility tree is the subset of the DOM tree. If you want to visualize Accessibility tree, there are few ways of doing that. One of this in Chrome you can open a new tab, navigate to chrome://accessibility and you’ll see tree for every tab opened.

alt text

These trees are hidden in the browser by default because it will slow down the browser’s performance. You can click on the “Show accessibility Tree” link to show it.

alt text

This is a raw dump of the Accessibility tree. It’s not obvious and difficult to understand, but it can give you an idea how browsers help assistive technologies create accessible information. More about chrome Accessibility tree you can find on Chrome's official website.

When we have some theory, let’s continue to improve accessibility.

Ensure that every HTML5 section does have aria-label or aria-labelledby property to clearly explain its purpose

It's important to know, that each <section> tag should have aria-label or aria-labelledby attributes from the accessibility point of view. Basically, when we write <section>...</section> we provide meaningful markup and in this case, we should explicitly declare that. That's what differentiate <section> from <div>. <div> can be meaningful as well, but it also can serve for styling purposes whereas <section> is always meaningful. Here's an example of the restaurant web-page that contains dinner menu:

<section aria-label="dinner menu">

If we have a declared title, we can point our section to that title by using id:

<section aria-labelledby="dinner-menu">
  <h3 id="dinner-menu">Dinner menu</h3>

If you want to use meaningful div for whatever reason there's another example:

<div role="region" aria-label="dinner menu">

<!-- or using aria-labelledby -->

<div role="region" aria-labelledby="dinner-menu">
  <h3 id="dinner-menu">Dinner menu</h3>

Here I used generic role="region" landmark and described it with aria attributes.


Ensure that sections or elements with the same roles are unique

You may face a case when two sections have the same roles. Here's what I mean:

<form role=“search”>
  <input placeholder="search globally on the site">
<form role=“search”>
  <input placeholder="enter your zip code to find a closest branch">

In this example, we have two searches, where the first one is a global search (content, articles, info, etc.) and another one is location search. As we mentioned earlier, it might not be obvious for some users. As before, "Aria attributes" come to help:

<form role=“search” aria-label="global search">
  <input placeholder="search globally on the site">
<form role=“search” aria-label="location search">
  <input placeholder="enter your zip code to find a closest branch">


Ensure that ARIA Attributes aren't redundant

As we can see from the previous examples "aria attributes" help to describe the purpose of the section and distinguish between identical parts of the page. However, sometimes they can be redundant. Here's an example:

<aside role="complementary">

<!-- or -->

<nav role="navigation">

Since we already have semantic aside and nav we don't need to add mentioned role attributes according to the HTML5 spec.

"AA" Level of Conformance

Provide an ability to skip repeated content

Most web-apps and sites on the internet have blocks that appear on every page. The very common example might be a top navigation. Sometimes these types of blocks can be very long (especially on news portals) and end user should be able to jump straight into article bypassing long sections using keyboard only. I found two real-world examples: American Airlines or Virgin Airlines. When you land on the page and hit "TAB" button a small "skip" popover appears.

alt text

"AAA" Level of Conformance

Provide enhanced contrast ratio for the text

We already covered this rule above. However, in order to meet AAA level we need to increase contrast ratio from 3:1 to 7:1 for a normal text and 4.5:1 for a large text.

more info


That's was a basic introduction to accessibility. Of course, there're way more requirements on each level. The main goal of this article is to provide a bridge to web accessibility standards where you can catch on it and continue your own journey. If you are interested to learn more please use links provided in this article. You're also very welcome to share your thoughts in the comments below!