Website Accessibility: WCAG, Screen Readers, Keyboard Navigation
A large bank's website had a "Submit Application" button. Visually it looked like a button. In the markup, it was a <div class="btn" onclick="...">. The NVDA screen reader didn't announce it as an interactive element, Tab skipped it, Enter didn't work. For 285,000 blind users in Russia, this bank simply didn't exist as an online service.
Semantic Markup: The Foundation of Everything
Most accessibility problems are solved with proper HTML, not additional ARIA attributes. <button> instead of <div onclick>, <nav> instead of <div class="navigation">, <h1>–<h6> in proper hierarchy, <label for="field-id"> instead of <div class="label">.
ARIA is needed where native HTML doesn't work: custom components — dropdown menus, tooltips, modals, tabs, accordions. This is where things get complex.
A typical error in custom dropdowns: the list of options opens, the screen reader doesn't know it's a combobox, doesn't announce the number of options, doesn't say which one is selected, focus doesn't move to the list when it opens. Proper implementation:
-
role="combobox"on the input -
aria-expanded="true/false"when opened/closed -
aria-controls="listbox-id"points to the list -
aria-activedescendant— ID of the currently selected element -
role="option"andaria-selectedon each option
This isn't theory, it's what screen readers test. NVDA + Chrome or VoiceOver + Safari — mandatory parts of QA.
Keyboard Navigation
Tab order must match the visual order of elements. If the "Cancel" button in HTML comes before "Confirm", but CSS swaps them visually — keyboard users are confused.
Focus trap in modals. When a modal opens, Tab should cycle only inside it, not escape its bounds. When closed — focus returns to the element that opened the modal. Without this, a keyboard user ends up at the start of the page after closing.
tabindex="-1" — the element doesn't enter the Tab sequence, but can receive focus programmatically. Used for elements that receive focus via JavaScript (section headers we scroll to after anchor navigation).
tabindex="1" and above — almost always a mistake. Explicit tabindex breaks natural order and creates unpredictable behavior. Manage order through DOM order, not through tabindex.
Skip links — a "Skip to Content" link, hidden visually but visible on Tab. Lets screen reader users skip repetitive navigation. position: absolute; left: -9999px in normal state, position: static on :focus.
Color and Contrast
WCAG 2.1 AA requires 4.5:1 contrast for regular text, 3:1 for large text (18px+ or 14px+ bold). AAA requires 7:1 and 4.5:1.
Most common violations: gray placeholder in inputs (#999 on white = 2.9:1), light gray secondary text, white text on pastel backgrounds.
Color shouldn't be the only indicator: "required fields are highlighted in red" without an asterisk or text indication — violation for colorblind users.
Checking tools: axe DevTools, WAVE, built-in Accessibility Inspector in Chrome DevTools. axe-core integrates into Playwright tests: automatic page checks against 80+ WCAG rules on every deploy.
Media Content and Dynamics
Images without alt — common basic failure. But alt should be meaningful: not alt="image_123.jpg", not alt="image", but a description of content relevant to context. Decorative images — alt="" (empty, not missing attribute).
Video must have captions. YouTube auto-captions aren't standard, they make mistakes. WebVTT files with correct captions for all educational and marketing video content.
Animations — a problem for users with vestibular disorders. @media (prefers-reduced-motion: reduce) — a media query that disables or slows animations for users with this setting in their OS. Parallax effects, infinite animations, scroll-based transitions should respect this preference.
WCAG 2.2 and What Changed
WCAG 2.2 became official in October 2023. New criteria include:
- 2.5.7 Dragging Movements (AA): all drag operations must have a keyboard alternative
- 2.5.8 Target Size (AA): minimum interactive element size 24x24px (not just touch)
- 3.2.6 Consistent Help (A): if there's contact/chat support, its location must be consistent across all pages
- 3.3.7 Redundant Entry (A): don't make users enter the same information twice in one session
Audit and Violation Remediation
Automated tools find about 30–40% of WCAG violations. The rest — only manual testing. Minimal manual testing scenario: go through the entire critical user flow (registration, purchase, feedback form) using only keyboard and screen reader.
Process
Audit starts with automatic scanning (axe, Lighthouse), then manual testing of key scenarios. Form a prioritized violation list: P1 (block usage), P2 (create difficulties), P3 (improvements). Fix through iterations, embed checks in CI to prevent regression accumulation.
Timeline
Website audit with report: 3–7 days. Fixing Level A/AA violations on an existing project: 3–8 weeks depending on scope and technical debt. New project development compliant with WCAG 2.2 AA: adds 15–25% to development timeline.







