Welcome to the Temple of Universal Knowledge! Just as the ancient Egyptians built pyramids with wide, accessible stairs for everyone who wanted to enter, we too must build web pages accessible to all users - including people with disabilities. Meet ARIA and semantic HTML - the keys to creating an inclusive internet!
Accessibility (abbreviated as a11y - "a" + 11 letters + "y") is ensuring that web pages can be used by everyone, regardless of their physical or technical capabilities.
Who benefits from accessible pages:
Egyptian analogy: Just as hieroglyphs were understandable to priests, scribes, and ordinary people at different levels, a web page should be accessible to all users.
1<!-- BAD - divs without meaning -->
2<div class="header">
3 <div class="nav">
4 <div class="nav-item">Home</div>
5 <div class="nav-item">About</div>
6 </div>
7</div>
8
9<div class="main-content">
10 <div class="article">
11 <div class="article-title">Article Title</div>
12 <div class="article-text">Article content...</div>
13 </div>
14</div>
15
16<!-- GOOD - semantic tags -->
17<header>
18 <nav>
19 <a href="/">Home</a>
20 <a href="/about">About</a>
21 </nav>
22</header>
23
24<main>
25 <article>
26 <h1>Article Title</h1>
27 <p>Article content...</p>
28 </article>
29</main>Why semantic tags are better:
1<!-- Page structure -->
2<header>Logo and main navigation</header>
3<nav>Navigation menu</nav>
4<main>Main page content (only one per page!)</main>
5<article>Standalone content unit (blog post, article)</article>
6<section>Thematic section of a document</section>
7<aside>Side content, related to main content</aside>
8<footer>Section or page footer</footer>
9
10<!-- Text content -->
11<h1>, <h2>, <h3>, <h4>, <h5>, <h6>Headings in hierarchy</h1>
12<p>Text paragraph</p>
13<blockquote>Quote</blockquote>
14<figure>Illustration with caption</figure>
15<figcaption>Caption for illustration</figcaption>
16
17<!-- Interactive elements -->
18<button>Button (for actions)</button>
19<a href="#">Link (for navigation)</a>
20<form>Form</form>
21<input>, <select>, <textarea>Form fields</input>ARIA is a set of attributes that extend HTML semantics and help assistive technologies (screen readers) understand the interface.
The Golden Rule of ARIA:
"Don't use ARIA if you can use semantic HTML!"
Roles tell the screen reader what a given element is:
1<!-- When semantic HTML is NOT enough -->
2
3<!-- Without role - it's not clear what this is -->
4<div class="navigation">
5 <a href="/">Home</a>
6 <a href="/products">Products</a>
7</div>
8
9<!-- With role="navigation" -->
10<div role="navigation">
11 <a href="/">Home</a>
12 <a href="/products">Products</a>
13</div>
14
15<!-- BEST - semantic tag (no role needed!) -->
16<nav>
17 <a href="/">Home</a>
18 <a href="/products">Products</a>
19</nav>Most popular ARIA roles:
1<!-- Navigation -->
2<div role="navigation">Menu</div>
3<!-- Better: <nav> -->
4
5<!-- Main content -->
6<div role="main">Main content</div>
7<!-- Better: <main> -->
8
9<!-- Button -->
10<div role="button" tabindex="0">Click</div>
11<!-- Better: <button> -->
12
13<!-- Alert -->
14<div role="alert">Error! Please fill in all fields.</div>
15
16<!-- Banner (page header) -->
17<div role="banner">Logo and navigation</div>
18<!-- Better: <header> -->
19
20<!-- Additional information -->
21<div role="complementary">Sidebar</div>
22<!-- Better: <aside> -->
23
24<!-- Article content -->
25<div role="article">Blog post</div>
26<!-- Better: <article> -->
27
28<!-- Search -->
29<div role="search">
30 <form>
31 <input type="search" aria-label="Search the site">
32 <button>Search</button>
33 </form>
34</div>
35
36<!-- Tab panel -->
37<div role="tabpanel" aria-labelledby="tab1">
38 Tab 1 content
39</div>NOTE: If you use a role on a div, you must also handle:
tabindex)aria-label adds a text description to an element that is read by screen readers:1<!-- Icon without text -->
2<button aria-label="Close window">
3 <svg><!-- X icon --></svg>
4</button>
5
6<!-- Social media link -->
7<a href="https://facebook.com" aria-label="Visit us on Facebook">
8 <img src="fb-icon.svg" alt="">
9</a>
10
11<!-- Search bar -->
12<input
13 type="search"
14 aria-label="Search products in the store"
15 placeholder="Search...">
16
17<!-- Hamburger menu button -->
18<button
19 class="hamburger"
20 aria-label="Open navigation menu"
21 aria-expanded="false">
22 <span></span>
23 <span></span>
24 <span></span>
25</button>
26
27<!-- Pagination navigation -->
28<nav aria-label="Page navigation">
29 <a href="?page=1">1</a>
30 <a href="?page=2" aria-current="page">2</a>
31 <a href="?page=3">3</a>
32</nav>When to use aria-label:
When NOT to use aria-label:
<label> in a formaltaria-labelledby connects an element to another element that serves as a label:1<!-- Modal dialog -->
2<div role="dialog" aria-labelledby="dialog-title" aria-describedby="dialog-desc">
3 <h2 id="dialog-title">Confirm Deletion</h2>
4 <p id="dialog-desc">Are you sure you want to delete this item? This action cannot be undone.</p>
5 <button>Delete</button>
6 <button>Cancel</button>
7</div>
8
9<!-- Tabs -->
10<div role="tablist">
11 <button role="tab" id="tab1" aria-controls="panel1">Description</button>
12 <button role="tab" id="tab2" aria-controls="panel2">Specifications</button>
13</div>
14
15<div role="tabpanel" id="panel1" aria-labelledby="tab1">
16 Detailed product description...
17</div>
18
19<div role="tabpanel" id="panel2" aria-labelledby="tab2">
20 Technical specifications...
21</div>
22
23<!-- Section with heading -->
24<section aria-labelledby="section-heading">
25 <h2 id="section-heading">Latest Articles</h2>
26 <article>...</article>
27 <article>...</article>
28</section>aria-describedby adds an extended description to an element:1<!-- Form field with help -->
2<label for="password">Password</label>
3<input
4 type="password"
5 id="password"
6 aria-describedby="password-requirements">
7<p id="password-requirements">
8 Password must contain at least 8 characters, including an uppercase letter and a number.
9</p>
10
11<!-- Button with additional context -->
12<button aria-describedby="delete-warning">
13 Delete Account
14</button>
15<p id="delete-warning">
16 This action is irreversible and will delete all your data.
17</p>
18
19<!-- Tooltip -->
20<button aria-describedby="tooltip1">
21 Save
22</button>
23<span id="tooltip1" role="tooltip" hidden>
24 Save changes to the document (Ctrl+S)
25</span>The
alt attribute is one of the most important accessibility elements. It describes an image for people who cannot see it.1<!-- GOOD - descriptive alt -->
2<img
3 src="pyramids-giza.jpg"
4 alt="Three pyramids in Giza at sunset, with camels in the foreground">
5
6<!-- GOOD - functional alt for a link -->
7<a href="/products">
8 <img src="shop-icon.svg" alt="Go to shop">
9</a>
10
11<!-- GOOD - empty alt for decorative images -->
12<img src="decorative-line.svg" alt="">
13
14<!-- BAD - alt identical to file name -->
15<img src="img_001.jpg" alt="img_001">
16
17<!-- BAD - unnecessary "photo", "image" -->
18<img src="cat.jpg" alt="Photo showing a cat">
19<!-- Better: alt="Cat sleeping on a couch" -->
20
21<!-- BAD - missing alt -->
22<img src="important-chart.jpg">
23<!-- Screen reader will read the file name! -->Rules for writing good alt text:
alt=""aria-describedby or <figcaption>1<!-- Decorative image (CSS background would be better) -->
2<img src="divider.svg" alt="">
3
4<!-- Image with text -->
5<img src="sale-banner.jpg" alt="50% Sale - today only!">
6
7<!-- Complex chart -->
8<figure>
9 <img
10 src="sales-chart.jpg"
11 alt="2024 Sales Chart"
12 aria-describedby="chart-description">
13 <figcaption id="chart-description">
14 The chart shows sales growth from 10,000 in January to 50,000 in December 2024.
15 The biggest jump occurred in November during Black Friday.
16 </figcaption>
17</figure>1<div class="button" onclick="submitForm()">
2 <img src="send-icon.svg">
3</div>
4
5<style>
6.button {
7 background: blue;
8 padding: 10px;
9 cursor: pointer;
10}
11</style>Problems:
1<button
2 type="submit"
3 aria-label="Submit form">
4 <img src="send-icon.svg" alt="">
5</button>
6
7<style>
8button {
9 background: blue;
10 padding: 10px;
11 cursor: pointer;
12 border: none;
13 color: white;
14}
15
16button:focus {
17 outline: 3px solid orange;
18 outline-offset: 2px;
19}
20</style>Advantages:
<button> - automatic keyboard supportaria-label describes the functiontype="submit" - clear functionStep by step:
Lighthouse will check:
Result: A report with a score of 0-100 and specific issues to fix.
Manual test:
Windows: NVDA (free) Mac: VoiceOver (built-in - Cmd+F5) Chrome: ChromeVox (extension)
Basic commands (NVDA):
A Chrome/Firefox extension that automatically detects accessibility problems:
Online tool: https://wave.webaim.org/
HTML and semantics:
<header>, <nav>, <main>, <article>)<main>Images:
alt attributealt=""Forms:
<label> or aria-labelrequired or aria-required="true")Keyboard navigation:
Colors and contrast:
ARIA:
role attributes are used correctlyaria-liverole="dialog" and aria-labelledbyTests:
Semantic HTML:
<button>, <nav>, <main>, <article> instead of divsARIA roles:
role="navigation", role="main", role="button"ARIA labels:
aria-label - adds a text descriptionaria-labelledby - links to an existing elementaria-describedby - adds an extended descriptionAlt in images:
alt="" for decorationsTesting:
Remember: Accessibility is not an extra feature - it's a fundamental part of building web pages. Just as the pyramids of Giza were built for all generations, web pages should be accessible to all users!