Day 10: Accessibility (a11y) Essentials
✅ Today you will learn
- Who needs accessibility (more people than you think)
- Semantic HTML as the foundation
- Keyboard access, focus and skip links
- ARIA: when to use it – and when not
- A 10-point accessibility audit
🏢 In the real world
Mr. Kapoor, a retired teacher with weak eyesight, uses his phone’s screen reader to order sweets. His granddaughter uses only the keyboard after a hand injury. If the Sharma Sweets website does not work for them, the shop loses loyal customers – and in many countries inaccessible sites also face legal action.
Who benefits?
Rule 1: use the right element
Inaccessible
- <div onclick="order()">Order</div>
- Not focusable with Tab
- Screen reader says just “Order”
- Enter key does nothing
Accessible
- <button type="button">Order</button>
- Focusable automatically
- Announced as “Order, button”
- Enter and Space work
<div onclick="alert('div clicked')" style="display:inline-block;padding:6px 12px;background:#e34f26;color:#fff;border-radius:6px">Fake button (div)</div>
<button type="button" onclick="alert('button clicked')">Real button</button>
<p>Press <kbd>Tab</kbd> inside this box: only the real button gets focus.</p>Rule 2: everything works with the keyboard
<style>
.skip{position:absolute;left:-999px} .skip:focus{left:8px;top:8px;background:#fff;padding:6px;border:2px solid #e34f26}
a:focus-visible,button:focus-visible,input:focus-visible{outline:3px solid #f59e0b;outline-offset:2px}
</style>
<a class="skip" href="#main">Skip to main content</a>
<nav><a href="#">Home</a> · <a href="#">Menu</a> · <a href="#">Contact</a></nav>
<main id="main" tabindex="-1"><h1>Sharma Sweets</h1>
<label>Search <input type="search"></label> <button>Go</button>
</main>| Do | Avoid |
|---|---|
| Keep the natural tab order (source order) | tabindex="1", "2"… positive values |
| Show a clear focus outline | outline: none without a replacement |
| Add a skip link as the first item | Keyboard traps (modals you cannot leave) |
| Use tabindex="-1" only to focus by script | Click-only actions on div/span |
Rule 3: text alternatives and clear language
- Meaningful
alton images;alt=""for decoration (Day 4). - Every form field has a visible <label> (Day 6).
- Link text says where it goes – never “click here” (Day 3).
- Video gets captions (<track kind="captions">), audio gets a transcript.
- Set
lang="en"on html andlang="hi"on Hindi text so screen readers use the right voice.
<p lang="hi">ताज़ी मिठाइयाँ, रोज़ सुबह।</p> <video controls width="320" src="/assets/img/tutorials/html/shop.mp4"> <track kind="captions" srclang="en" label="English" src="captions-en.vtt"> </video>
Rule 4: colour and contrast
<p style="color:#bbb">Light grey text on white – hard to read (contrast 1.9:1) ❌</p> <p style="color:#555">Dark grey on white – easy to read (contrast 7.5:1) ✅</p> <p><span style="color:red">Red = sold out</span> ❌ colour only</p> <p><span style="color:#b91c1c">✖ Sold out</span> ✅ icon + text + colour</p>
WCAG asks for at least 4.5 : 1 for normal text and 3 : 1 for large text. Chrome DevTools shows the contrast ratio when you inspect a colour.
ARIA – the last resort
<button type="button" aria-label="Close offer banner">✕</button>
<button type="button" aria-expanded="false" aria-controls="m1"
onclick="const o=this.getAttribute('aria-expanded')==='true';this.setAttribute('aria-expanded',!o);document.getElementById('m1').hidden=o;">☰ Menu</button>
<ul id="m1" hidden><li>Home</li><li>Menu</li></ul>
<p>Cart: <span aria-live="polite" id="c">0 items</span>
<button type="button" onclick="c.textContent=(parseInt(c.textContent)+1)+' items'">Add ladoo</button></p>| ARIA | Purpose |
|---|---|
| aria-label | Name for an icon-only control (✕, ☰, 🔍) |
| aria-labelledby / aria-describedby | Point to visible text that names/describes an element |
| aria-expanded | Tells if a menu/accordion is open |
| aria-live="polite" | Announces changing content (cart count, form status) |
| aria-hidden="true" | Hide decorative icons from screen readers |
| role="alert" | Urgent messages like errors |
If a native HTML element already does the job (button, nav, label, details), use it instead of ARIA. Wrong ARIA is worse than no ARIA.
A 10-point quick audit
- Unplug the mouse – can you use the whole page with Tab, Enter, Space, Esc?
- Is the focus outline always visible?
- Does every image have suitable alt?
- Does every field have a label?
- Is there exactly one h1 and a logical heading order?
- Are link and button texts clear out of context?
- Contrast ≥ 4.5:1?
- Zoom to 200% – does content still fit?
- html lang set; Hindi parts marked lang="hi"?
- Run Lighthouse (Chrome DevTools → Lighthouse → Accessibility) and fix the list.
🏅 Job skills unlocked today
Practice tasks
🏋️ Practice – do it yourself
<div onclick="buy()">🛒</div> <img src="ladoo.jpg"> <input placeholder="Mobile">Show solution
<button type="button" onclick="alert('added')" aria-label="Add to cart">🛒</button>
<img src="/assets/img/tutorials/html/ladoo-400.webp" alt="Besan ladoo, ₹500 per kg" width="160" height="120">
<label for="mob">Mobile</label> <input id="mob" type="tel" autocomplete="tel">Quick quiz
🧠 Quick Quiz – test yourself
Interview corner
💼 Interview Corner
What is the first rule of ARIA?
Do not use ARIA if a native HTML element or attribute provides the semantics and behaviour you need. Native elements come with keyboard support and correct roles for free.
How do you test accessibility?
Automated tools (Lighthouse, axe) for quick wins, then manual checks: keyboard-only navigation, screen reader (NVDA/TalkBack/VoiceOver), zoom 200%, contrast checks, and ideally testing with disabled users.
Summary
- Native semantic elements give accessibility for free.
- Everything must work with the keyboard, with visible focus and a skip link.
- Text alternatives, labels, captions, lang and contrast ≥ 4.5:1.
- ARIA fills gaps only; audit with keyboard, screen reader and Lighthouse.
Day 11: interactive HTML – details/summary, dialog, progress, meter, template and data attributes.
