DEV Community

Cover image for Web Accessibility Guide: Building Inclusive Websites in 2023
Aarav Joshi
Aarav Joshi

Posted on

Web Accessibility Guide: Building Inclusive Websites in 2023

As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world!

The internet has transformed how we interact with information, but not everyone experiences it equally. As a web developer with over a decade of experience, I've seen firsthand how thoughtful, inclusive design practices can dramatically improve accessibility for all users.

When I first started coding, accessibility was often an afterthought. Today, I recognize it as essential to good web development. Let me share practical approaches to building websites that work for everyone, regardless of their abilities or how they access the web.

Semantic HTML: The Foundation of Accessible Websites

Semantic HTML forms the bedrock of accessible web development. When we use HTML elements based on their intended meaning rather than their appearance, we create a document structure that's intelligible to both humans and machines.

Screen readers and other assistive technologies rely on semantic structure to navigate content. Using proper heading hierarchies (h1 through h6) creates a logical outline of your page, giving users a mental map of your content.

Consider this example of poorly structured HTML:

<div class="heading">Welcome to Our Site</div>
<div class="subheading">About Our Services</div>
<div class="content">We offer the following services...</div>
Enter fullscreen mode Exit fullscreen mode

And compare it with semantically structured HTML:

<h1>Welcome to Our Site</h1>
<h2>About Our Services</h2>
<p>We offer the following services...</p>
Enter fullscreen mode Exit fullscreen mode

The second example communicates the structure clearly to all users, including those using screen readers.

Landmarks such as <nav>, <main>, <header>, and <footer> help users navigate directly to significant sections of your page. For example:

<header>
  <h1>Company Name</h1>
  <nav aria-label="Main">
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/products">Products</a></li>
      <li><a href="/contact">Contact</a></li>
    </ul>
  </nav>
</header>
<main>
  <article>
    <h2>Featured Content</h2>
    <!-- Content here -->
  </article>
</main>
<footer>
  <p>Copyright 2023</p>
</footer>
Enter fullscreen mode Exit fullscreen mode

This structure allows users to jump directly to the navigation or main content, saving considerable time for screen reader users.

ARIA Attributes: Enhancing HTML Semantics

ARIA (Accessible Rich Internet Applications) attributes enhance HTML semantics when native elements aren't sufficient. They communicate states, properties, and roles to assistive technologies.

A key principle to remember is that ARIA should supplement HTML, not replace it. As the first rule of ARIA states: "If you can use a native HTML element with the semantics and behavior you require, do so."

For interactive components like tabs, accordions, or modal dialogs, ARIA becomes essential:

<div role="tablist">
  <button id="tab1" role="tab" aria-selected="true" aria-controls="panel1">Product Features</button>
  <button id="tab2" role="tab" aria-selected="false" aria-controls="panel2">Technical Specs</button>
</div>
<div id="panel1" role="tabpanel" aria-labelledby="tab1">
  <p>Our product includes these amazing features...</p>
</div>
<div id="panel2" role="tabpanel" aria-labelledby="tab2" hidden>
  <p>Technical specifications include...</p>
</div>
Enter fullscreen mode Exit fullscreen mode

The JavaScript to support this would manage focus and update aria-selected states when tabs are activated.

Live regions notify screen reader users of dynamic content changes:

<div aria-live="polite" aria-atomic="true">
  <p id="status-message"></p>
</div>
Enter fullscreen mode Exit fullscreen mode
document.getElementById('status-message').textContent = 'Your form has been submitted successfully';
Enter fullscreen mode Exit fullscreen mode

The "polite" value ensures the announcement won't interrupt the user, while "atomic" means the entire region will be announced when changed.

Keyboard Accessibility: No Mouse Required

Not everyone can use a mouse. Some users rely exclusively on keyboards or alternative input devices. I've learned that testing keyboard navigation is one of the quickest ways to identify accessibility issues.

Every interactive element should be accessible and operable via keyboard, maintaining a logical tab order that follows the visual layout. Users should be able to:

  1. Navigate using the Tab key
  2. Activate buttons and links with Enter or Space
  3. Operate complex widgets with arrow keys and other key combinations

Focus indicators must be clearly visible. Many developers remove these for aesthetic reasons, leaving keyboard users unable to track their position on the page:

/* Poor practice */
:focus {
  outline: none;
}

/* Better practice */
:focus {
  outline: 3px solid #4d90fe;
}

/* Even better - accommodate high contrast mode too */
:focus {
  outline: 3px solid #4d90fe;
  outline-offset: 2px;
}

/* Focus-visible for modern browsers */
:focus:not(:focus-visible) {
  outline: none;
}

:focus-visible {
  outline: 3px solid #4d90fe;
  outline-offset: 2px;
}
Enter fullscreen mode Exit fullscreen mode

For custom components, explicitly managing focus becomes crucial. For example, when opening a modal:

function openModal() {
  // Display the modal
  const modal = document.getElementById('modal');
  modal.hidden = false;

  // Set focus to the first focusable element
  const firstFocusable = modal.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
  firstFocusable.focus();

  // Trap focus within the modal
  modal.addEventListener('keydown', trapFocus);
}

function trapFocus(e) {
  // Implementation of focus trapping
  // ...
}
Enter fullscreen mode Exit fullscreen mode

I once worked on a website where users struggled with form submission. The issue? A custom button that looked great but wasn't keyboard accessible. After fixing this, completion rates improved significantly.

Color Contrast and Visual Design

Color contrast affects readability for everyone, especially users with low vision or color blindness. The Web Content Accessibility Guidelines (WCAG) recommend specific contrast ratios:

  • 4.5:1 for normal text
  • 3:1 for large text (18pt or 14pt bold)
  • 3:1 for visual elements that convey information

I use tools like the Chrome DevTools color contrast analyzer or WebAIM's contrast checker to verify my designs. Here's how to improve contrast in CSS:

/* Poor contrast */
.button {
  background-color: #add8e6; /* Light blue */
  color: #808080; /* Gray text */
}

/* Improved contrast */
.button {
  background-color: #add8e6; /* Light blue */
  color: #000000; /* Black text */
}
Enter fullscreen mode Exit fullscreen mode

Color should never be the only method of conveying information. Icons, patterns, or text labels should accompany color cues:

<!-- Poor practice -->
<p>Fields marked in red are required</p>
<input type="text" class="required-field">

<!-- Better practice -->
<p>Fields marked with an asterisk (*) are required</p>
<label for="name">Name *</label>
<input id="name" type="text" aria-required="true">
Enter fullscreen mode Exit fullscreen mode

I've found that designing for high contrast from the start leads to cleaner, more usable interfaces that benefit all users.

Alternative Text for Images

Alternative text (alt text) provides textual descriptions of images for users who cannot see them. Writing effective alt text requires considering the image's purpose and context.

For informative images, describe the content and function concisely:

<img src="chart-quarterly-sales.png" alt="Bar chart showing quarterly sales increasing from Q1 to Q4 2022, with Q4 reaching $1.2 million">
Enter fullscreen mode Exit fullscreen mode

For functional images like icons in buttons:

<button>
  <img src="search-icon.svg" alt="Search">
</button>

<!-- Or better yet -->
<button aria-label="Search">
  <img src="search-icon.svg" alt="">
</button>
Enter fullscreen mode Exit fullscreen mode

Decorative images that add no information should have empty alt attributes:

<img src="decorative-divider.png" alt="">
Enter fullscreen mode Exit fullscreen mode

Complex images like infographics may need extended descriptions:

<figure>
  <img src="data-workflow.png" alt="Diagram showing data processing workflow">
  <figcaption>
    Our data processing workflow moves through four stages: collection, 
    validation, analysis, and reporting, with feedback loops at each stage.
  </figcaption>
</figure>
Enter fullscreen mode Exit fullscreen mode

I've developed the habit of asking myself: "If I couldn't see this image, what would I need to know about it?" This simple question leads to better alt text decisions.

Progressive Enhancement and Robust Code

Progressive enhancement builds websites in layers, starting with accessible HTML and adding CSS and JavaScript as enhancements rather than requirements. This approach ensures core functionality remains available regardless of technology limitations.

I structure my projects to work without JavaScript first:

<form action="/subscribe" method="post">
  <label for="email">Email address</label>
  <input type="email" id="email" name="email" required>
  <button type="submit">Subscribe</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Then enhance with JavaScript for a better experience:

document.querySelector('form').addEventListener('submit', async (e) => {
  e.preventDefault();
  const email = document.getElementById('email').value;

  try {
    const response = await fetch('/api/subscribe', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ email })
    });

    if (response.ok) {
      document.getElementById('status').textContent = 'Successfully subscribed!';
    } else {
      throw new Error('Subscription failed');
    }
  } catch (error) {
    document.getElementById('status').textContent = 'Error subscribing. Please try again.';
  }
});
Enter fullscreen mode Exit fullscreen mode

Fault tolerance is crucial. Always validate user input on both client and server, and handle errors gracefully:

// Input validation
function validateEmail(email) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return regex.test(email);
}

// Graceful degradation
if (!window.fetch) {
  // Provide alternative implementation
  // or inform users to upgrade their browser
}
Enter fullscreen mode Exit fullscreen mode

I've learned that spending time on robust error handling pays dividends in user satisfaction and reduced support tickets.

Responsive Design for All Devices and Zoom Levels

Responsive design accommodates users across a spectrum of devices, screen sizes, and zoom levels. Using flexible layouts with relative units ensures content remains accessible regardless of how it's viewed.

I prefer a mobile-first approach with CSS:

/* Base styles for mobile */
.container {
  width: 100%;
  padding: 1rem;
}

/* Adjust for larger screens */
@media (min-width: 768px) {
  .container {
    max-width: 750px;
    margin: 0 auto;
  }
}
Enter fullscreen mode Exit fullscreen mode

Flexible images prevent horizontal scrolling:

img {
  max-width: 100%;
  height: auto;
}
Enter fullscreen mode Exit fullscreen mode

Text should be readable without zooming (minimum 16px for body text) and should reflow when zoomed to 200%:

body {
  font-size: 1rem; /* 16px in most browsers */
  line-height: 1.5;
}

p {
  max-width: 70ch; /* For optimal readability */
}
Enter fullscreen mode Exit fullscreen mode

Touch targets need adequate spacing and size (at least 44×44 pixels) for motor-impaired users:

button, .interactive-element {
  min-height: 44px;
  min-width: 44px;
  padding: 0.5rem 1rem;
  margin: 0.25rem;
}
Enter fullscreen mode Exit fullscreen mode

I regularly test at different viewport sizes and zoom levels to ensure my designs remain functional and usable.

Inclusive Form Design

Forms are often the most challenging aspect of web accessibility. Clear labeling, error prevention, and helpful feedback create a better experience for all users.

Always associate labels with form controls:

<label for="username">Username</label>
<input id="username" name="username" type="text">
Enter fullscreen mode Exit fullscreen mode

Use fieldsets and legends to group related controls:

<fieldset>
  <legend>Shipping Address</legend>
  <div>
    <label for="street">Street</label>
    <input id="street" name="street" type="text">
  </div>
  <!-- Additional address fields -->
</fieldset>
Enter fullscreen mode Exit fullscreen mode

Input types should match their intended data:

<input type="email" id="email" autocomplete="email">
<input type="tel" id="phone" autocomplete="tel">
<input type="date" id="birthdate">
Enter fullscreen mode Exit fullscreen mode

Error messages should be clear and linked to their relevant fields:

<label for="password">Password</label>
<input id="password" type="password" aria-describedby="password-error">
<div id="password-error" class="error" aria-live="polite"></div>
Enter fullscreen mode Exit fullscreen mode
function validatePassword(password) {
  if (password.length < 8) {
    const errorElement = document.getElementById('password-error');
    errorElement.textContent = 'Password must be at least 8 characters';
    return false;
  }
  return true;
}
Enter fullscreen mode Exit fullscreen mode

I've found that taking time to plan form validation and error handling leads to higher conversion rates and satisfied users.

Testing and Continuous Improvement

Accessibility isn't a one-time task but an ongoing commitment. I incorporate multiple testing methods into my workflow:

Automated tools like Lighthouse, axe, or WAVE provide a quick baseline assessment:

// Example of programmatic accessibility testing with axe-core
const axe = require('axe-core');

axe.run(document).then(results => {
  if (results.violations.length) {
    console.error('Accessibility violations found:', results.violations);
  } else {
    console.log('No accessibility violations detected!');
  }
});
Enter fullscreen mode Exit fullscreen mode

Manual testing with keyboard navigation and screen readers reveals issues automated tools miss. I use NVDA or VoiceOver to test critical user journeys.

User testing with people who have disabilities provides invaluable insights. Nothing compares to observing real users interact with your website.

I document accessibility features in a statement that outlines compliance levels and known limitations:

<a href="/accessibility">Accessibility Statement</a>
Enter fullscreen mode Exit fullscreen mode

This transparency builds trust with users who depend on accessible websites.

The Business Case for Accessibility

Beyond ethical considerations, accessibility makes business sense. Accessible websites:

  • Reach a wider audience (15-20% of the population has a disability)
  • Improve SEO through semantic HTML and proper structure
  • Reduce legal risk from potential discrimination claims
  • Enhance usability for all users, including those in situational limitations

I've seen organizations transform their approach to accessibility when they understand these practical benefits.

Conclusion

Building accessible websites isn't about checking boxes for compliance—it's about creating experiences that work for everyone. The practices I've shared represent core principles that have guided my work for years.

When we design with accessibility in mind, we build better websites for all users. The extra effort pays dividends in user satisfaction, broader reach, and simpler maintenance. In my experience, accessible design leads to cleaner code, more thoughtful user experiences, and ultimately more successful digital products.

The web was designed to be universally accessible. By embracing these inclusive development practices, we honor that vision and create a digital world that truly serves everyone.


101 Books

101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.

Check out our book Golang Clean Code available on Amazon.

Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!

Our Creations

Be sure to check out our creations:

Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | JS Schools


We are on Medium

Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva

Top comments (0)