Front-end Web Development Good Practices: Accessibility

My workplace: standing desk, laptop, notes, phone, and coffee.
My workplace

Accessibility is about making websites usable for everyone, benefiting not only people with disabilities but also those using mobile devices or having slow network connections.

Inspired by

This article draws significant inspiration from the “Accessibility” section of MDN Web Docs. It summarizes the practices in my own words and provides examples of both good and bad code.

Always use the right HTML elements for the right purpose

HTML elements come with some default styles and they are keyboard-friendly. For example, users can move between buttons using the Tab key and activate their selection using Space, Return, or Enter.

❌ Bad

<div> Play video </div>

✅ Good

<button> Play video </button>

Care for descriptive content

Descriptive content helps Screen Readers, which are tools for people with visual impairments. These tools change text into speech, letting users hear and navigate the content.

Structure the content with headings, paragraphs, and lists.

❌ Bad

<span style="font-size: 3em">Heading</span>
<br /><br /> 
This is my content.
<br /><br />
<span style="font-size: 2.5em">Subheading</span>
<br /><br />
This is my subcontent.

✅ Good

<h1>Heading</h1>
<p>This is my content.</p>
<h2>Subheading</h2>
<p>This is my subcontent.</p>

Use clear language

Use full words. Instead of 5-7, write 5 to 7. Avoid abbreviations. Instead of writing Jan, write January.

❌ Bad

<a href="whales.html">click here</a>

✅ Good

<a href="whales.html">Learn more about whales</a>

Update the styling to fit your design, but ensure it still functions as expected

While CSS allows for extensive customization of HTML elements, maintaining user expectations through correct semantics is crucial. Elements should be styled to fit the design, but not to the extent that they no longer behave or appear as expected.

Emphasis elements

The standard bold and italic text conventions are recognizable.

❌ Bad

strong, em {
  font-style: normal;
  font-weight: normal;
}

✅ Good

em {
  font-style: italic;
}
strong {
  font-weight: bold; 
}

Abbreviations

The recognized styling convention for abbreviations is a dotted underline.

❌ Bad

abbr {
  text-decoration: none;
}

✅ Good

abbr {
  text-decoration: underline dotted;
}

Links

Standard link conventions include underlining and color changes based on the link’s state. Interaction with the link should provide user feedback, and changes in states should be noticeable. The pointer cursor and outline are essential for accessibility and should not be removed.

❌ Bad

a {
  text-decoration: none;
  color: black;
  cursor: default;
}
a:hover {
  color: black;
}

✅ Good

a {
  text-decoration: underline;
  color: blue;
  cursor: pointer;
}
a:hover {
  color: red;
}

Form elements

While it’s possible to style form focus/hover states for consistency across browsers or to match page design, it’s crucial not to eliminate the visual feedback form elements receive when focused, as users rely on these cues.

❌ Bad

input:focus {
  outline: none;
}

✅ Good

input:focus {
  outline: 2px solid blue;
}

Tables

Ensure table headers are prominent (typically bold) and use zebra striping for easier row parsing.

❌ Bad

table {
  width: 100%;
}
th {
  font-weight: normal;
  background-color: white;
}
tr:nth-child(even) {
  background-color: white;
}

✅ Good

table {
  width: 100%;
}
th {
  font-weight: bold;
  background-color: #f2f2f2;
}
tr:nth-child(even) {
  background-color: #f2f2f2;
}

Ensure good contrast between text and background colors

Use online contrast checking tools, like WebAIM’s Color Contrast Checker, to conform to WCAG criteria. High contrast also improves readability on glossy screens in bright environments. Don’t solely rely on color for information; use symbols, like asterisks, for important markers.

❌ Bad

p {
  background-color: lightgray;
  color: white;
}

✅ Good

p {
  background-color: white;
  color: black;
}

Use unobtrusive JavaScript

Basic functions should ideally work without JavaScript, using built-in browser functionality where possible. Unobtrusive JavaScript, which enhances rather than builds functionality, is recommended.

As the friends at GOV.UK rightfully say there are plenty of reasons why JavaScript fails. A browser extension could block it, the visitor might be on a flaky network, there could be a DNS issue, … the possibilities are endless. That’s why progressive enhancement should be at the core of your web development

Source: New on the web: How to detect disabled JavaScript in CSS

❌ Bad

JavaScript is directly embedded into the HTML markup through the onsubmit attribute. If JavaScript is disabled or not supported, the form validation will not work at all.

<form onsubmit="return validateForm()">
  <input type="text" id="inputID">
  <input type="submit" value="Submit">
</form>

<script>
function validateForm() {
  let input = document.getElementById('inputID');

  if(input.value === '') {
    alert('Form field cannot be empty!');
    return false;
  }

  return true;
}
</script>

✅ Good

We are using unobtrusive JavaScript to validate a form. If JavaScript is disabled or not supported, the form will still submit, but without client-side validation.

document.getElementById('formID').addEventListener('submit', function(e) {
  let isValid = true;
  let input = document.getElementById('inputID');

  if(input.value === '') {
    isValid = false;
    alert('Form field cannot be empty!');
  }

  if(!isValid) {
    e.preventDefault();
  }
});

Limit mouse-specific events

Consider mouse-specific events like mouseover, mouseout, dblclick may not be keyboard-accessible. Pair them with similar keyboard events like focus and blur.

❌ Bad

// Only works for mouse users
element.onmouseover = function() {
  // Show zoomed image
};
element.onmouseout = function() {
  // Hide zoomed image
};

✅ Good

// Works for both mouse and keyboard users
element.onmouseover = element.onfocus = function() {
  // Show zoomed image
};
element.onmouseout = element.onblur = function() {
  // Hide zoomed image
};

Use WAI-ARIA features only when necessary

WAI-ARIA (Web Accessibility Initiative – Accessible Rich Internet Applications) is a specification written by the W3C, defining a set of additional HTML attributes that can be applied to elements to provide additional semantics and improve accessibility wherever it is lacking.

❌ Bad

There is no form tag, and the div doesn’t provide any semantic information about its content. The input field lacks a type, placeholder, or aria-label, making it less accessible and harder for users to understand its purpose.

<div>
  <input type="text">
</div>

✅ Good

The form has a clear role attribute of “search”, making it accessible. The input field has the type “search”, a placeholder to guide users, and the aria-label attribute to provide a descriptive label for screen readers.

<form role="search">
  <input type="search" name="q" placeholder="Search query" aria-label="Search through site content" />
</form>

❌ Bad

There are no aria-live or aria-atomic attributes. This means that screen readers will not announce updates to the content, making it potentially confusing for users with visual impairments.

<section>
    <h1>Random quote</h1>
    <blockquote><p></p></blockquote>
</section>

✅ Good

The aria-live="assertive" attribute will ensure screen readers announce updates to the content immediately, and the aria-atomic="true" attribute ensures the entire contents of the section are read out as one unit.

<section aria-live="assertive" aria-atomic="true">
    <h1>Random quote</h1>
    <blockquote><p></p></blockquote>
</section>

Create custom audio and video controls

Most browsers do not provide keyboard-accessibility for audio and video controls. Additionally, the native controls’ styling and functionality vary across different browsers.

❌ Bad

<video src="video.mp4" controls></video>

✅ Good

<div>
  <video id="myVideo" src="video.mp4"></video>
  <button onclick="playPause()">Play/Pause</button>
</div>

<script>
  var myVideo = document.getElementById("myVideo");

  function playPause() {
    if (myVideo.paused)
      myVideo.play();
    else
      myVideo.pause();
  }
</script>

Don’t disable zoom

Avoid using user-scalable=no or user-scalable=0 in the viewport, as many users rely on zoom to view website content. If zooming disrupts the user interface, consider an alternative such as a control to increase the text size without breaking the UI.

❌ Bad

<meta name="viewport" content="width=device-width, user-scalable=no">

✅ Good

<meta name="viewport" content="width=device-width">

Summary

Make sure the app is easy to see for people with low vision, color blindness, or who are blind. Also, don’t forget to make it keyboard-friendly. Just remember, accessibility is all about doing your best, not about being perfect 100% of the time, which, let’s be real, is pretty much impossible.

By Huong Nguyen

I am a full-stack software engineer. I have working experience with Java, Node.js, Angular, PostgreSQL, Jenkins, and OpenShift. I enjoy spending time with my son and wife on weekends. I am also a book lover. All posts and content I share solely represent my own views and do not represent the views of my employer.

1 comment

Leave a comment

Your email address will not be published. Required fields are marked *