We use cookies to enhance your experience on the site
CodeWorlds

Accessibility in HTML - Building for Everyone

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!

What is Accessibility (A11y)?

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:

  • Blind and visually impaired people (screen readers)
  • Deaf and hard of hearing people (captions, transcriptions)
  • People with motor difficulties (keyboard navigation)
  • Elderly people (larger fonts, high contrast)
  • Users with slow connections (lightweight 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.

Semantic Tags vs Divs with Roles

Semantic HTML - The First Step to Accessibility

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:

  • Screen readers automatically recognize the structure
  • Search engines index content better (SEO)
  • Browsers provide default behaviors
  • Easier code maintenance
  • Keyboard navigation works out-of-the-box

Key Semantic Tags

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 - Accessible Rich Internet Applications

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!"

ARIA Roles - Defining an Element's Role

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:

  • Keyboard navigation (
    tabindex
    )
  • Event handling (Enter, Space for buttons)
  • States (aria-pressed, aria-expanded)

aria-label - Adding a Label

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:

  • Element has only an icon (no text)
  • Visible text is unclear or incomplete
  • Context is not obvious

When NOT to use aria-label:

  • Element already has clear, visible text
  • You can use
    <label>
    in a form
  • Image already has an appropriate
    alt

aria-labelledby - Linking to an Existing Label

aria-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 - Additional Description

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 Importance of the alt Attribute in Images

The

alt
attribute is one of the most important accessibility elements. It describes an image for people who cannot see it.

Best Practices for alt

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:

  1. Describe the content, not the form ("Sleeping cat" instead of "Photo")
  2. Context matters - what does the image add to the content?
  3. Be concise - 125-150 characters max
  4. Decorative images - use empty
    alt=""
  5. Text images - transcribe the text exactly
  6. Complex diagrams - also use
    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>

Example: Accessible vs Inaccessible Component

Inaccessible Button

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:

  • No semantics (div instead of button)
  • Doesn't work with keyboard (Tab, Enter)
  • No text description (only icon)
  • Screen reader doesn't know it's a button

Accessible Button

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:

  • Semantic
    <button>
    - automatic keyboard support
  • aria-label
    describes the function
  • Focus outline for keyboard users
  • type="submit"
    - clear function

How to Test Accessibility

1. Lighthouse (Chrome DevTools)

Step by step:

  1. Open DevTools (F12)
  2. "Lighthouse" tab
  3. Check "Accessibility"
  4. Click "Generate report"

Lighthouse will check:

  • Color contrast
  • Alt attributes on images
  • ARIA attributes
  • Heading hierarchy
  • Form labels
  • And much more...

Result: A report with a score of 0-100 and specific issues to fix.

2. Keyboard Navigation

Manual test:

  1. Put away the mouse
  2. Use only the keyboard:
    • Tab - move to the next element
    • Shift+Tab - go back to the previous one
    • Enter - activate link/button
    • Space - check checkbox, activate button
    • Arrow keys - navigate in select, radio buttons
  3. Check:
    • Can you see the focus outline?
    • Is the order logical?
    • Can you reach everywhere?
    • Are there no "focus traps"?

3. Screen Reader

Windows: NVDA (free) Mac: VoiceOver (built-in - Cmd+F5) Chrome: ChromeVox (extension)

Basic commands (NVDA):

  • Ctrl - stop reading
  • Insert+Down Arrow - read everything
  • H - jump to next heading
  • K - jump to next link
  • B - jump to next button
  • F - jump to next form field

4. axe DevTools (extension)

A Chrome/Firefox extension that automatically detects accessibility problems:

  • Installation: Chrome Web Store -> "axe DevTools"
  • Usage: F12 -> "axe DevTools" tab -> "Scan ALL"

5. WAVE (WebAIM)

Online tool: https://wave.webaim.org/

  • Enter the page URL
  • You'll receive a visual analysis with marked errors

Accessibility Checklist

HTML and semantics:

  • [ ] I use semantic tags (
    <header>
    ,
    <nav>
    ,
    <main>
    ,
    <article>
    )
  • [ ] Heading hierarchy is logical (h1 -> h2 -> h3)
  • [ ] Each page has exactly one
    <main>

Images:

  • [ ] All images have an
    alt
    attribute
  • [ ] Decorative images have empty
    alt=""
  • [ ] Alt texts are descriptive and concise

Forms:

  • [ ] Every field has a
    <label>
    or
    aria-label
  • [ ] Validation errors are clear and readable
  • [ ] Required fields are marked (
    required
    or
    aria-required="true"
    )

Keyboard navigation:

  • [ ] I can reach everywhere using only Tab
  • [ ] Focus outline is visible
  • [ ] Tab order is logical
  • [ ] Interactive elements respond to Enter/Space

Colors and contrast:

  • [ ] Text contrast is at least 4.5:1 (normal text)
  • [ ] Text contrast is at least 3:1 (large text 18px+)
  • [ ] Information is not conveyed ONLY by color

ARIA:

  • [ ] ARIA is used only when semantic HTML is not enough
  • [ ]
    role
    attributes are used correctly
  • [ ] Dynamic content has
    aria-live
  • [ ] Modals have
    role="dialog"
    and
    aria-labelledby

Tests:

  • [ ] Lighthouse Accessibility: 90+
  • [ ] Tested with a screen reader
  • [ ] Tested with keyboard only

Summary

Semantic HTML:

  • Use
    <button>
    ,
    <nav>
    ,
    <main>
    ,
    <article>
    instead of divs
  • Provides automatic accessibility
  • Better for SEO and maintenance

ARIA roles:

  • role="navigation"
    ,
    role="main"
    ,
    role="button"
  • Use ONLY when semantic HTML is not enough
  • Requires additional keyboard and state handling

ARIA labels:

  • aria-label
    - adds a text description
  • aria-labelledby
    - links to an existing element
  • aria-describedby
    - adds an extended description

Alt in images:

  • Describe content, not form
  • Empty
    alt=""
    for decorations
  • Context matters

Testing:

  • Lighthouse (DevTools)
  • Keyboard navigation
  • Screen reader (NVDA, VoiceOver)
  • axe DevTools
  • WAVE

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!

Go to CodeWorlds