Accessible Front-End Development

Introduction

The web is pretty great, isn’t it?


It provides unlimited access to information, communication, media, and more at all hours of the day, seven days a week. Without our favorite websites we feel lost and frustrated—perhaps even cut off from the rest of the world.


Imagine now that your mouse has disappeared. How are you supposed to play your favorite games, or navigate your favorite sites? Consider what would happen if your monitor stopped working. How would you watch your favorite shows or browse the latest photos on Instagram?


You may be accustomed to the presence of your mouse or monitor, but if every webpage was built with accessible development in mind, the sudden disappearance of those tools wouldn’t affect your ability to use the internet. In fact, there are many non-sighted people with no use for a monitor at all, or people with physical limitations that prevent them from using a mouse. These people should still be able to use the internet to its fullest extent.


Accessible development means that your webpage should be fully usable to people of every ability, disability, and socioeconomic background. It’s a necessary component of any and all applications that interact directly with human beings.


In this guide, you'll learn basic tactics to achieve accessible HTML for your website. You'll also learn how to avoid common mistakes that violate accessibility standards.


Presenting Information

Semantic HTML - Meaningful Tags for Meaningful Websites

A web page may present its information in a way that visually makes sense, but the actual information in the HTML document might be fragmented and nonsensical. Think of this situation like the optical illusion below.


To the left, a wooden chair in an empty room. To the right, a chair that appears fragmented and disjointed.

Image from Mighty Optical Illusions


A sighted user may see a website’s content like the chair to the left—complete and properly arranged. But a screen reader may parse the actual HTML of the website like the photo to the left—broken and unusable. As we know, usability should not be a matter of perspective. The chair should be a chair from any viewpoint.


HTML is a tree of nested nodes—called tags—with semantically-significant tag names. If nodes are not properly labelled or grouped together, assistive technologies such as screen readers may struggle to present your site’s content in a meaningful way. A screen reader is an assistive technology that reads and describes the content displayed on a computer, phone, or other device.


View the below snippet of HTML. The <section> HTML tag represents a section of a site, the <h3> HTML tag represents a heading, and the <p> tag represents a paragraph. So if your site needed an "Introduction" heading and a paragraph of introductory text, you could represent it as the following:


<section class="intro-section">
  <h1>Introduction</h1>
  <p>Welcome to my website!</p>
</section>

Introduction

Welcome to my website!


Because the <h3> and <p> tags are semantically significant HTML tags, screen readers can actually communicate to the user that the "Introduction" text is a heading, and the "Welcome to my website!" paragraph is secondary text. And with the <section> tag, we know that these items are grouped together. Moving items outside of particular sections will create confusion, though, even if the appearance is the same. See the following example and preview:

<section class="intro-section">
  <h3>Introduction</h3>
</section>
<section>
  <p>Welcome to my website!</p>
</section>

Introduction

Welcome to my website!


Because the introductory paragraph is in a different section, the association between the paragraph and the heading is broken. Some assistive technologies may not interpret them as grouped together.

Accessible CSS - CSS Only Fools the Eyes

Cascading Style Sheets (CSS) are an incredibly useful tools that allow us to style our HTML elements in appealing ways. It can, however, be abused in ways that mask poor site accessibility. Consider the following code example and preview:

<style>
  .intro-section {
    display: flex;
    flex-direction: column-reverse;
  }
</style>
<section class="intro-section">
  <p>Welcome to my website!</p>
  <h1>Introduction</h1>
</section>


Welcome to my website!

Introduction


With the use of the display: flex and flex-direction: column-reverse CSS properties, we can make it appear as though the heading precedes the introductory paragraph, even though it comes later in the HTML document. But this trick only fools the eyes—it won’t fool a screen reader. To people with assistive technology, this text will still read as "Welcome to my website! Introduction," which doesn’t make much sense.


CSS should never determine order of content. It should also never be used to add critical content to the page, as CSS cannot be interpreted by screen readers. For example:


<style>
  .old-price {
    text-decoration: line-through;
  }
  .old-price:before, .new-price:before {
    content: "$";
  }
  .new-price {
    color: red;
  }
</style>
<section class="item-price">
  <span class="old-price">10.99</span>
  <span class="new-price">5.99</span>
</section>


10.99 5.99

Visually, the meaning of this bit of text is clear. The original price, $10.99, has been discounted to $5.99, as evidenced by the strikethrough and text coloring. We know that we’re dealing with dollars thanks to the dollar symbol tacked on by the :before pseudo-element (see "pseudo-element" explanation at the bottom of this section), but a lot of key information is conveyed via the CSS styling, not the HTML itself. Erase the CSS, and here’s what’s actually on the page:


10.99 5.99

The meaning of these two numbers is significantly less clear. What is their purpose? What is the difference between them? Are they measurements of weight? Of length? We can’t tell.


Assistive technologies cannot interpret CSS styling. A screen reader will interpret these two values as "ten-dot-ninety-nine" and "five-point-nine-nine," which hardly conveys their actual meaning.


A pseudo-element is an element that exists only from a visual standpoint on the page. It’s not actually inserted into the HTML document. The:before selector, in particular, visually appends a child node before the actual HTML children of a particular element. The :after selector does the same after the HTML children of a particular element.


Maintaining Aesthetics - Don't Sacrifice Style

We could rectify the problems in our previous example by (1) explicitly stating what the values represent and (2) placing the dollar sign in the actual HTML:


<section class="item-price">
  <span class="old-price">Old Price: $10.99</span>
  <span class="new-price">New Price: $5.99</span>
</section>

Old Price: $10.99 New Price: $5.99

You may notice, however, that this is not the most aesthetically appealing way to communicate a discounted price. The strikethrough paired with the red text was certainly more attention-grabbing. CSS must not replace meaningful content on the page, but it can still be used to enhance the communication of information. You can still achieve a pleasing design while maintaining accessibility.

Many years ago, a popular CSS and Javascript library called Bootstrap introduced a CSS class called .sr-only, or screen reader only. This class can be added to any HTML element to render it invisible to the human eye but fully readable to screen readers. The CSS for this class is as follows:


.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  border: 0;
}


Note that this block of styling doesn’t use display: none or visibility: hidden, as these properties can actually remove the affected element from the HTML document in some browsers. This styling instead shrinks, crops, and masks the content beyond what browsers can display. It thus uses the strictly visual nature of CSS to its advantage—allowing content to be present without disrupting the webpage’s aesthetic considerations.


Bootstrap is an open source library, so you can and should add the .sr-only class to any web page that needs it. Let’s strategically use .sr-only in our discounted price example:


<style>
  .old-price {
    text-decoration: line-through;
  }
  .new-price {
    color: red;
  }
  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0,0,0,0);
    border: 0;
  }
</style>
<section class="item-price">
  <span class="old-price"><span class="sr-only">Old Price:</span>$10.99</span>
  <span class="new-price"><span class="sr-only">New Price:</span>$5.99</span>
</section>


Old Price:$10.99 New Price:$5.99

We’re back to what appears to be our original design—but with some critical accessibility improvements:





Though we can’t see all the text, a screen reader will read this document as "Old Price: ten dollars and ninety-nine cents. New Price: five dollars and ninety nine cents." The visual appearance and textual content are both reasonable and meaningful.


If we are mindful of how we build our websites, we should never have to sacrifice aesthetics for accessibility, or vice versa.


Accessible Images - Every Picture Is Worth Some Words

As we’ve already discussed, assistive technologies are unable to interpret visual content. And what could be more purely visual than an image?


Assistive technology developers are aware of the fundamental role that images play in conveying information. They have thus developed ways for screen readers to essentially "read" images. Of course, we have yet to develop a technology that can perfectly translate images into words. Screen readers can interpret images only when we’re willing to provide descriptions of them. Here’s how images are represented in HTML:


<img src="https://cdn.pixabay.com/photo/2019/09/24/06/54/dog-4500444_960_720.jpg" />


Open source image from Pixabay


You may be tempted to place your image description in the <img> tag, but this is not possible. Note the lack of </img> closing tag. The <img> tag is self-closing because it cannot contain children elements. So where should you put your image description?


The <img> tag has a unique alt attribute. Just like how physical attributes on a person may change our capabilities, HTML attributes modify the behavior and function of the HTML elements they’re applied to. Above, you already see the src, or "source" attribute which points to the location of the image we want to display. The src attribute tells the browser to fetch the image from that web location and insert it within that particular <img> tag.


The alt attribute is the "alternative text" of an image. It is the image description that assistive technologies automatically find and read. In the event that an image cannot load or no longer exists at the provided location, the alternative text will be displayed in the image’s place. The meaning of the image therefore cannot be lost in the image’s absence.


The alt attribute works as follows:


<img src="https://cdn.pixabay.com/photo/2019/09/24/06/54/dog-4500444_960_720.jpg" alt="A dark brown hound sits with its back to the camera, gazing sadly over its shoulder at the viewer. The hound is outside, sitting between a patch of tall grass and a dirt path." />


A dark brown hound sits with its back to the camera, gazing sadly over its shoulder at the viewer. The hound is outside, sitting between a patch of tall grass and a dirt path.

Open source image from Pixabay


Note that the description is much more specific than simply writing "dog." A picture is worth a thousand words, or so the saying goes. Do your best to describe as much of the image of as possible. If the image is purely decorative (meaning that it adds absolutely no meaning to the content of the webpage), you may use an empty alt="" attribute, which will hide the image's presence from screen readers. Without this attribute, screen readers will read the file name of the image, which is often long and nonsensical. Always consider very carefully whether an empty alt="" attribute is the right option, as the image in question may be more significant than you initially anticipate


Accessible Icons - Icons Aren’t Always Universal

Iconography is a supremely useful way to cross language and literacy barriers. Certain symbols are easily recognizable and perhaps even culturally universal to sighted individuals. Using icons in web development can therefore help users quickly navigate or understand your website.


But like images, icons are visual elements. There are accessibility considerations to make whenever you add an icon to your site.


If your icons are typical image files (.png, .jpeg, .jpg, .gif, etc), they can be placed inside an <img> tag with a descriptive alt attribute.


Icon fonts such as FontAwesome, however, present a new challenge. Icon fonts treat the icons as typographical glyphs, rather than images. This means that the icon can be sized, inserted, and colored the same way you would size, insert, and recolor the letter "A", or an exclamation point.


FontAwesome would thus represent an icon as the following:


<i class="fa fa-book"></i>



The <i> tag semantically represents italicized text, but it is rarely used for that purpose in practice. FontAwesome usually relies on this tag to insert icons. The :before CSS pseudo-element then visually appends the icon glyph within every <i> tag of format <i class="fa fa-*"></i>.


A book icon is clearly visible to the human eye. But because this icon is not an image with alt text, screen readers have no way of detecting that the book icon is there. In fact, to screen readers, that <i> tag is completely empty and meaningless.


Here we can bring back .sr-only to make our icons meaningful:


<i class="fa fa-book"><span class="sr-only">Book Icon</span></i>


Book Icon

The appearance is completely unchanged, but the meaning of the icon is now detectable to screen readers.


Accessible Multimedia - Closed Captioning Provided By…

Abilities and disabilities are varied. Some users may not be able to hear content on your site. Other users may be sensitive to flashing lights in video and .gif files. Some users may need a keyboard, rather than a mouse, to play audio and video.


If using audio and video, both the <audio> and <video> tags accept a track attribute. The track attribute specifies a subtitle track for the sound in the audio/video element. With subtitles, users who are hard of hearing can still understand and enjoy the content you are trying to share.


You must also allow users to control the audio/video using their keyboard. To do this, you may add the controls attribute to the audio/video. This specifies that the browser should determine the keyboard controls for these multimedia files. This can be tricky, though, as some browsers may have different keyboard controls, or may not support keyboard controls at all. Unfortunately, if you wish to have consistent, custom controls, you must implement them yourself through Javascript.


Fair warning, the process for attaching a caption track and implementing custom button controls for HTML audio/video can be rather involved. If you're interested, here is a guide on subtitling provided by the Mozilla Web Docs. However, it may be easier to simply upload your content to YouTube (or some other popular video provider), and then embed the YouTube video in your HTML. This is easier for several reasons:



If your video or .gif contains flashing lights, add visual, audible, and textual warnings. These warnings should be placed or timed so that users are able to effectively navigate away from the content before the flashing lights begin.


Interactive Elements

Accessible Forms - Form Formation Done Right

Many websites require users to input information. This information could be usernames, passwords, credit card information, addresses and more. A common way to input information are HTML forms. Forms usually consist of an input where a user can type or click to indicate a value of some sort, and an accompanying label to indicate the purpose of that form. A properly developed form can be easily interpreted by screen readers:


<form>
  <label for="address">Address:</label>
  <input id="address" type="text" name="useraddress">
</form>


There are a few key attributes that must be included to make this form accessible.



Other forms require a bit more configuration to be accessible. Checkboxes, for example, should be grouped together in a <fieldset> with a <legend> . This will indicate to screen readers that the checkboxes are answering the question presented by the <legend>.


<fieldset>
  <legend>Favorite Colors:</legend>
  <input id="blue" type="checkbox" name="favorite-colors" value="blue">
  <label for="blue">Blue</label><br>
  <input id="red" type="checkbox" name="favorite-colors" value="red">
  <label for="red">Red</label><br>
  <input id="yellow" type="checkbox" name="favorite-colors" value="yellow">
  <label for="yellow">Yellow</label><br>
</fieldset>    


Favorite Colors:



The same goes for radio buttons:


<fieldset>
  <legend>Favorite Color:</legend>
  <input id="blue" type="radio" name="favorite-color" value="blue">
  <label for="blue">Blue</label><br>
  <input id="red" type="radio" name="favorite-color" value="red">
  <label for="red">Red</label><br>
  <input id="yellow" type="radio" name="favorite-color" value="yellow">
  <label for="yellow">Yellow</label><br>
</fieldset>


Favorite Color:



Using semantically meaningful HTML elements is the best way to ensure form accessibility. If you do not like the appearance of the fieldset, buttons, or labels, you can easily override the default styling with custom CSS. Using CSS to change the form appearance will not affect a screen reader’s ability to interpret the information.


Keeping Focus - Don't Erase the Outline

When you use a mouse to hover over a link like this one, you may notice that your cursor changes into a little hand with a raised pointer finger. This should indicate to you that (1) the link is clickable and (2) your mouse is in the right position to execute a click on the element. Similarly, you can enter text into an input by clicking on the input and typing.


When you click on an interactive element such as a link, button, or input, you bring that element into focus. Focus indicates that you have selected a particular HTML element to interact with. Once clicked, the browser will continue focusing on that element until you select a new element to bring into focus.


Imagine if a user was relying exclusively on keyboard controls. Instead of using a mouse, users rely on the "tab" key to bring individual elements into focus. Users will tab through an application one interactive element at a time until they reach the end of the document. Tabbing is the primary way to navigate between interactive elements using a keyboard, but arrow keys may be used to switch between interaction options (such as the options provided by a group of radio buttons).


Screen readers will read out the element currently in focus. However, there are sighted users who don’t require a screen reader but still use keyboard controls. Without the pointer cursor provided by the mouse, they need a visual indication that an element is in focus and interactive.


Browsers automatically provide a visual indication of focus. It is usually an outline of some sort. In Chrome this looks like:


The words 'A Link' colored purple with an underline, indicating a link, and a glowing blue outline around the link.

Many people feel that this outline is ugly or distracting, and thus try to remove it using CSS. Do not do this! This outline is crucial for a multitude of reasons:



You may change the color of the focus outline, but it is best to keep focus consistent across webpages.


Accessible Buttons - To Button or Not to Button

<button> and <a> tags, otherwise known as buttons and hyperlinks, are accessible without much effort. Screen readers are programmed to detect these elements as clickable, interactive elements. Simply ensure that the content between the opening and closing <button> and <a> tags is meaningful. For example, if your button is a heart-shaped "like" button, make sure there is explanatory text that describes the appearance and purpose of the heart icon. The heart icon alone cannot be interpreted.


You may have noticed that browsers automatically apply certain styling conventions to semantically significant HTML elements. Buttons, for example, look like this by default in the Google Chrome Browser:



No CSS was explicitly styled for this button. The code is simply:


<button onclick="myFunction()">I'm a button!</button> 


The styling that is automatically applied to buttons in Chrome is represented by the following:


button {
  -webkit-appearance: button;  
  -webkit-writing-mode: horizontal-tb !important;
  text-rendering: auto;
  color: buttontext;
  letter-spacing: normal;
  word-spacing: normal;
  text-transform: none;
  text-indent: 0px;
  text-shadow: none;
  display: inline-block;
  text-align: center;
  align-items: flex-start;
  cursor: default;
  background-color: buttonface;
  box-sizing: border-box;
  margin: 0em;
  font: 400 11px system-ui;
  padding: 1px 7px 2px;
  border-width: 1px;
  border-style: solid;
  border-color: rgb(216, 216, 216) rgb(209, 209, 209) rgb(186, 186, 186);
  border-image: initial;
}


That seems like a lot of properties to override if you want a button to look different from the default. To avoid overriding so many different CSS properties, many developers choose to use the meaningless <div> tag instead of <button>:


<style>
  .my-btn {
    cursor: pointer;
    background: green;
    color: white;
    border: 1px solid darkgreen;
    padding: 5px;
    display: inline-block;
  }
</style>
<div class="my-btn" onclick="myFunction()">I'm a button!</div> 


I'm a button!

In the above example, we’ve made a <div> that functions like a button for sighted users. It looks like a green button, and when we hover over it, we see that it’s clickable.


While this decision seems well-intended, it often leads to accessibility violations. The <button> tag is specifically designed to indicate interactivity to screen readers. It is focusable, tabbable, and interactive. The <div> tag, on the other hand, is not, and must be specially configured to fulfill the same role as a <button>.


<style>
  .my-btn {
    cursor: pointer;
    background: green;
    color: white;
    border: 1px solid darkgreen;
    padding: 5px;
    display: inline-block;
  }
</style>
<div class="my-btn" tabindex="0" role="button" aria-pressed="false" onclick="myFunction()" onkeydown="myKeyFunction()">I'm a button!</div> 


I'm a button!

Note four new attributes on the <div> tag: tabindex , role, aria-pressed, and onkeydown. The tabindex attribute allows users to navigate to the button using the tab key and bring the button into focus. The role="button" attribute will allow screen readers to describe this <div> as a <button> to users.


The last attribute is aria-pressed. This attribute isn’t always necessary. If the button acts as a toggle, activating a certain state once pressed, this attribute is logical to include. aria-pressed="true" means that the toggle is active. aria-pressed="false", meanwhile, means that the toggle is inactive.


An alternative to aria-pressed is aria-expanded. If clicking the button opens a menu or dropdown, aria-expanded="true" indicates that the menu/dropdown is open. On the other hand, if the button submits a value, neither of these tags are necessary, as there is no state change induced by the button press.


aria-pressed and aria-expanded are Accessible Rich Internet Applications (ARIA) attributes. These attributes are used to mimic behavior already provided by many semantic HTML elements, as evidenced by their role in mimicking buttons here. There are many other ARIA attributes that allow developers to essentially "hack" new versions of semantic HTML elements. For explanations and tutorials on ARIA, see the Mozilla Web Docs on the subject. It is still easier and more desirable, however, to simply use the semantic HTML elements as they were designed.


What becomes more complicated is that you must implement different functions for clicks and key presses on the button. Traditional <button> tags have click and keyboard support pre-baked into their functionality. With these specially-configured "fake" buttons, you must build this functionality yourself. This likely means using Javascript to code what happens when either the space or enter keys are pressed.


While a "fake" <div> button is easier to style, it is much more difficult to make it properly interactive. It is best to use <button> tags whenever possible, overriding styles as needed and only using "fake" interactive elements when absolutely necessary.


Final Words

The examples presented in this guide are only a sample of issues commonly encountered when building web pages in HTML and CSS. The general rule is that a logically structured HTML document is the best way to ensure accessibility. Rely on semantic HTML elements with real text rather than CSS and meaningless <div> elements. Always include alternative text for images, and consider caption tracks and flashing light warnings for multimedia. Do not sacrifice style and aesthetics, but do not use them to impede accessibility.


Following these simple rules will maintain HTML accessibility in nearly all situations. Oftentimes, accessibility violations occur only because developers try to "hack" HTML structure to more easily achieve a particular design or function. Don’t do this. If the web design can’t fit into a typical HTML, it probably needs to be re-evaluated.


If you wish to learn more about website accessibility, please consult the online resources provided by the Web Accessibility Initiative, an organization devoted to ensuring accessibility across the web. You can also explore the Mozilla Web Docs on the subject, which are provided by the creators of major technologies such as the Mozilla Firefox browser.


About the Author

An avatar image of Michelle Pine

Michelle Pine is a fourth year Computer Science & Design combined major at Northeastern University. Professional, she operates as a full-stack developer and designer with a particular interest in front-end development and client-facing technology. Her past experiences include working at Boston Children's Hospital as UI/UX Designer and Graphics Innovator, as well as working as a Software Engineering Co-op at BookBub. You can learn more about Michelle at michellepine.com, LinkedIn, or Github.