On this page
Basic web accessibility with HTML
What is web accessibility?
Web accessibility (often abbreviated as a11y) means designing and developing pages that can be used by everyone, including people with visual, auditory, motor, or cognitive disabilities.
According to the World Health Organization, more than 15% of the world's population lives with some form of disability. Making your site accessible is not just a best practice -- in many countries it is a legal requirement.
The 4 principles of accessibility (POUR)
The WCAG are based on four fundamental principles:
- Perceivable — Information must be perceivable (see, hear, read)
- Operable — The interface must be usable with different devices (keyboard, voice)
- Understandable — Content and interface must be comprehensible
- Robust — Content must work with different assistive technologies
Alternative text for images
The alt attribute is the primary accessibility tool for images:
<!-- Informative image: describe the content -->
<img src="chart.png" alt="Bar chart showing a 25% increase in sales">
<!-- Decorative image: empty alt -->
<img src="decorative-border.png" alt="">
<!-- Functional image (button/link): describe the action -->
<a href="/home">
<img src="logo.svg" alt="Go to home page">
</a>The rule is simple:
- If the image conveys information, describe that information
- If the image is decorative, use
alt=""(empty, do not omit the attribute) - If the image is inside a link or button, describe the action
Heading structure
Headings (<h1> through <h6>) create an outline of the page that screen readers use for navigation. Users can jump between headings as if it were a table of contents:
<h1>HTML Course</h1>
<h2>Chapter 1: Introduction</h2>
<h3>What is HTML?</h3>
<h3>History of HTML</h3>
<h2>Chapter 2: Basic Elements</h2>
<h3>Text tags</h3>Essential rules:
- Do not skip levels (do not go from
<h2>to<h4>) - One
<h1>per page - Headings should reflect the logical hierarchy of the content
Keyboard navigation
Many users navigate exclusively with the keyboard (Tab, Enter, Escape, arrow keys). Make sure that:
All interactive elements are focusable
Native HTML elements like <a>, <button>, <input>, and <select> are focusable by default. If you create interactive elements with <div> or <span>, they will not be focusable unless you add tabindex="0":
<!-- Correct: native button, automatically focusable -->
<button type="button">Open menu</button>
<!-- Incorrect: non-focusable and non-accessible div -->
<div class="button" onclick="openMenu()">Open menu</div>
<!-- Better: always use native elements when possible -->Skip links
A "skip link" allows keyboard users to jump directly to the main content without having to tab through the entire navigation:
<body>
<a href="#main" class="skip-link">Skip to main content</a>
<nav><!-- many navigation links --></nav>
<main id="main">
<!-- main content -->
</main>
</body>Accessible forms
Forms are one of the most critical areas for accessibility:
Explicit labels
Every form field must have an associated <label>:
<!-- Explicit association with for/id -->
<label for="username">Username</label>
<input type="text" id="username" name="username">
<!-- Implicit association (label wraps the input) -->
<label>
Email address
<input type="email" name="email">
</label>Additional descriptions with aria-describedby
When a field needs additional instructions:
<label for="password">Password</label>
<input type="password" id="password" aria-describedby="password-req">
<p id="password-req">Minimum 8 characters, include a number and an uppercase letter.</p>Groups of related fields
Use <fieldset> and <legend> to group related fields:
<fieldset>
<legend>Shipping address</legend>
<label for="street">Street</label>
<input type="text" id="street" name="street">
<label for="city">City</label>
<input type="text" id="city" name="city">
</fieldset>Essential ARIA attributes
ARIA (Accessible Rich Internet Applications) provides attributes that improve accessibility when native HTML is not sufficient:
| Attribute | Use |
|---|---|
aria-label |
Accessible name when there is no visible text |
aria-labelledby |
References an element that acts as a label |
aria-describedby |
References an element with additional description |
aria-required |
Indicates that a field is required |
aria-hidden |
Hides an element from assistive technologies |
aria-current |
Indicates the current element in a set (active page, current step) |
role |
Defines the semantic role of an element |
The most important ARIA rule: do not use ARIA if you can achieve the same thing with native HTML. A <button> is better than a <div role="button">.
Color contrast
The contrast between text and background must meet the following ratios (WCAG AA):
- Normal text: minimum ratio of 4.5:1
- Large text (18px bold or 24px normal): minimum ratio of 3:1
- Interface elements (borders, icons): minimum ratio of 3:1
Tools like the accessibility inspector in Chrome DevTools allow you to check contrast directly in your browser.
Practice
- Add a skip link: Create a page with extensive navigation and add a "Skip to main content" link as the first element of the
<body>that points to theidof the<main>. - Build an accessible form: Create a contact form where every
<input>has an associated<label>usingfor/id, at least one field usesaria-describedbyfor additional instructions, and radio buttons are wrapped in a<fieldset>with<legend>. - Audit your images: Review an existing page and make sure all informative images have a descriptive
altand all decorative images havealt="".
In the next lesson, we will learn how to build complete and functional forms.
<!-- Accessible form -->
<form aria-labelledby="form-title">
<h2 id="form-title">Contact form</h2>
<div>
<label for="full-name">Full name *</label>
<input
type="text"
id="full-name"
name="full-name"
required
autocomplete="name"
aria-required="true"
>
</div>
<div>
<label for="email">Email address *</label>
<input
type="email"
id="email"
name="email"
required
autocomplete="email"
aria-required="true"
aria-describedby="email-hint"
>
<small id="email-hint">Example: [email protected]</small>
</div>
<div role="group" aria-labelledby="preference-label">
<p id="preference-label">Preferred contact method:</p>
<label>
<input type="radio" name="contact" value="email"> Email
</label>
<label>
<input type="radio" name="contact" value="phone"> Phone
</label>
</div>
<button type="submit">Send message</button>
</form>
<!-- Skip link to jump to content -->
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<header>
<nav aria-label="Main menu">
<ul role="list">
<li><a href="/" aria-current="page">Home</a></li>
<li><a href="/courses">Courses</a></li>
<li><a href="/blog">Blog</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<h1>Welcome to the site</h1>
<!-- Informative image -->
<img src="team.jpg"
alt="Our team of 5 developers at the office"
width="800" height="450">
<!-- Decorative image -->
<img src="decoration.svg" alt="" role="presentation">
<!-- Icon with alternative text -->
<button type="button" aria-label="Close dialog">
<svg aria-hidden="true" focusable="false">
<!-- X icon -->
</svg>
</button>
</main>
Sign in to track your progress