♿ धडा 06 — Accessibility: प्रत्येकजण फलक वाचू शकतो
📍 तुम्ही इथे आहात: 12 पैकी धडा 06 · मागे: lesson-05-state-components · पुढे: lesson-07-frameworks
📦 या ब्रँचमध्ये काय आहे
धडे 01–05, आणि फलक प्रत्येकासाठी चालतो की नाही हे ठरवणारा धडा: keyboard, प्रत्येक control साठी नावे, contrast, focus, live regions, आणि ARIA चे प्रामाणिक नियम.
🧒 5 वर्षांच्या मुलाला समजावल्यासारखे
कल्पना करा की तुम्ही दिवे बंद असताना फलक वाचत आहात, आणि एक मदतनीस तो मोठ्याने वाचून दाखवत आहे (screen reader). किंवा तुमचे हात mouse वापरू शकत नाहीत, म्हणून तुम्ही Tab ने पुढे जाता आणि Enter ने दाबता. किंवा कडक उन्हात, जिथे पांढऱ्यावरचा फिकट राखाडी मजकूर नाहीसा होतो.
या सगळ्यांसाठी चालणारा फलक म्हणजे वेगळी खास आवृत्ती नाही — तो तोच फलक आहे, फक्त योग्य प्रकारे बांधलेला:
- Keyboard ⌨️ — Tab प्रत्येक control पर्यंत पोहोचतो, गोष्टी ज्या क्रमाने दिसतात त्याच क्रमाने;
focus असलेली गोष्ट स्पष्टपणे focused दिसते (
:focus-visible); पहिला Tab एक skip link देतो, म्हणजे कोणालाही प्रत्येक वेळी nav मधून चालत जावे लागत नाही. - नावे 🏷️ — प्रत्येक input ला
<label>आहे; प्रत्येक image लाaltआहे; फक्त icon असलेल्या button लाaria-labelआहे. मदतनीस एखादा control काय आहे ते सांगू शकत नसेल, तर तो अस्तित्वातच नाही. - Contrast + फक्त रंगावर अवलंबून नाही 🎨 — मुख्य मजकूर त्याच्या पार्श्वभूमीशी 4.5:1; शब्द किंवा icon शिवाय "लाल असलेल्या म्हणजे errors" असे कधीच नाही.
- घोषणा 📣 — जेव्हा फलक पान reload न होता बदलतो
(cards load झाले, "Zoya is on the board", "Could not load"), तेव्हा एक live region
(
role="status"/aria-live="polite") मदतनीसाला सांगतो. आपली status ओळ आणि form संदेश नेमके तेच आहेत. - हालचाल —
prefers-reduced-motionचा आदर करा; animation मुळे लोक आजारी पडू शकतात.
आणि ARIA चा पहिला नियम: वाईट ARIA पेक्षा ARIA नसणे चांगले. आधी योग्य
element वापरा (lesson 02); HTML ला जे सांगता येत नाही तेच सांगण्यासाठी aria-*
वापरा.
🗺️ आकृती
flowchart TB
kb["⌨️ keyboard: Tab order = visual order · :focus-visible · skip link first"]
nm["🏷️ names: label for= · alt · aria-label on icon buttons"]
ct["🎨 contrast 4.5:1 · never colour alone · reduced motion honoured"]
lv["📣 live regions: role=status / aria-live=polite announce changes"]
ar["⚠️ ARIA last: the right element first; no ARIA > bad ARIA"]
kb --> nm --> ct --> lv --> ar
❓ काय
- Focus चा क्रम DOM च्या क्रमानुसार चालतो. 0 पेक्षा मोठा
tabindexवापरू नका;tabindex="0"custom control ला focusable बनवतो,-1त्याला फक्त code मधूनच focusable बनवतो. - Roles, names, values: सहाय्यक तंत्रज्ञानाला control चा role (button),
name ("Enrol") आणि state (आपल्या theme toggle वरचे
aria-pressed="true") दिसतात. Semantic HTML तिन्ही देते; ARIA फक्त उणिवा भरून काढते. - Live regions:
aria-live="polite"थांबा येईपर्यंत वाट पाहतो;role="alert"(आपला form संदेश) मध्येच बोलतो. फक्त महत्त्वाचे असेल तेच जाहीर करा. - List load होत असताना त्यावरचे
aria-busy="true"मदतनीसाला अर्धवट काढलेली list न वाचण्यास सांगते. - Contrast: सामान्य मजकुरासाठी 4.5:1, मोठ्या मजकुरासाठी आणि UI borders साठी 3:1 — DevTools colour picker मध्ये हे प्रमाण दाखवते.
- Testing: फक्त keyboard ने एक फेरी; एक screen reader (VoiceOver ⌘F5, NVDA, Narrator); automated checks (axe, Lighthouse) कदाचित 30% पकडतात — बाकीचे म्हणजे तुम्ही आत्ताच केलेली keyboard ची फेरी.
- कायदा: WCAG 2.2 AA हे सामान्य मानक आहे (आणि अनेक ठिकाणी ती कायदेशीर गरज आहे).
🤔 का
कारण लोकांना वगळणारा फलक त्यांच्यासाठी थोडा नव्हे, तर पूर्णपणे मोडलेला असतो. कारण इथली प्रत्येक गोष्ट इतर सगळ्यांनाही मदत करते: keyboard support power users ना मदत करतो, contrast उन्हात मदत करतो, live regions मंद networks वर मदत करतात, आणि semantics तुमच्या tests मजबूत बनवतात. आणि कारण नंतर जोडण्यापेक्षा सुरुवातीपासून टिकवून ठेवणे खूपच स्वस्त आहे.
🔧 कसे (या repo मध्ये)
फलकासोबत येतात: एक .skip link (फक्त focus असतानाच दिसणारी), :focus-visible
outlines, प्रत्येक control साठी labels, avatars वर alt (alt="" — नाव
अगदी शेजारीच आहे), list status वर role="status" aria-live="polite",
form संदेशावर role="alert", load होत असताना list वर aria-busy, आणि
theme toggle वर aria-pressed.
🧪 करून पाहा
python3 ui/mock_api.py
# 1) keyboard only — no mouse at all: Tab (skip link) → Enter → filter a class → Tab to the form → enrol a student
# 2) screen reader: macOS ⌘F5 (VoiceOver) or Windows Narrator. Listen to the list, the labels, and the message after enrolling.
# 3) break a name: remove aria-label from the theme button and hear "button" with no name. Put it back.
# 4) contrast: DevTools → pick .status colour → the contrast ratio is shown. Try making --muted lighter and see it fail.
# 5) the robot pass:
python3 ui/smoke_test.py # lang, one h1, labels, alt, skip link + live region
✅ तपासा — तुम्हाला काय दिसायला हवे
तुम्ही mouse ला हात न लावता नावनोंदणी पूर्ण केली, आणि प्रत्येक पायरीवर focus ring दिसत होती. Screen reader ने "Zoya is on the board" जाहीर केले, कारण तो संदेश live region मध्ये राहतो. Smoke test च्या पाच a11y तपासण्या pass होतात.
🏁 तुम्ही आत्ताच काय सिद्ध केले
तोच फलक mouse, keyboard आणि screen-reader वापरणाऱ्या सगळ्यांची सेवा करतो — कारण HTML जे म्हणते तोच त्याचा अर्थ असतो आणि बदल जाहीर केले जातात.
⚠️ नेहमीच्या चुका
- त्याऐवजी काहीही न देता
outline: none— keyboard users आपली जागा हरवतात <button>वापरण्याऐवजी button असल्याचे नाटक करणाऱ्या<div>वरaria-label- सगळीकडे
aria-live="assertive"(ते सतत मध्येच बोलते) - errors साठी फक्त रंग हाच संकेत
- फक्त automated tool ने test करून विजय जाहीर करणे
🏭 प्रत्यक्ष वापरात हे का महत्त्वाचे: accessibility audits, खरेदीच्या अटी आणि खटले खरे आहेत, पण रोजचे कारण सोपे आहे: तुमच्या users पैकी लक्षणीय भागाला याची गरज असते, आणि जो फलक ते चालवू शकत नाहीत तो ते सरळ सोडून जातील.
⏭️ पुढे
भाग 2 सुरू होतो: फलक पाठवणे. आधी, frameworks — React, Vue आणि Svelte काय automate करतात, आणि vanilla कधी पुरेसे असते.
git checkout lesson-07-frameworks