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>
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>
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>
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>
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>
document.getElementById('status-message').textContent = 'Your form has been submitted successfully';
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:
- Navigate using the Tab key
- Activate buttons and links with Enter or Space
- 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;
}
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
// ...
}
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 */
}
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">
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">
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>
Decorative images that add no information should have empty alt attributes:
<img src="decorative-divider.png" alt="">
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>
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>
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.';
}
});
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
}
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;
}
}
Flexible images prevent horizontal scrolling:
img {
max-width: 100%;
height: auto;
}
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 */
}
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;
}
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">
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>
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">
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>
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;
}
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!');
}
});
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>
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)