Complete Guide to Web Accessibility: Automated Testing with Lighthouse / axe, WCAG Criteria Development, Keyboard Operation, and Screen Reader Support
This post is also available in 日本語.
Introduction
Web accessibility is an essential element to ensure that all users can comfortably use websites. Especially for elderly users or those with visual or hearing impairments, a lack of proper accessibility measures can restrict access to information.
This article provides a detailed explanation of specific methods for improving web accessibility, including automating accessibility tests using Lighthouse and axe, establishing evaluation criteria based on WCAG guidelines, improving screen reader support, optimizing color contrast, and introducing ARIA landmarks. By continuously implementing these initiatives, let's create websites that are easier for more users to use.
Automating Accessibility Tests (Monitoring Setup with Lighthouse / axe)
Automating accessibility tests enables continuous quality assurance. Lighthouse and axe-core are prominent tools that are easy to integrate into the development workflow.
Accessibility Testing Using Lighthouse
Lighthouse is an open-source auditing tool provided by Google that can automatically check the following points:
- Accessibility (web content usability)
- Performance (page speed)
- SEO (search engine optimization)
- Best Practices (security and mobile compatibility)
- PWA (Progressive Web App suitability)
How to Run Lighthouse
- Open the target page in Chrome.
- Open DevTools by pressing F12 or Cmd + Option + I (Mac) / Ctrl + Shift + I (Windows).
- Select the Lighthouse tab and check "Accessibility".
- Click "Analyze page load" to analyze.
Accessibility Testing Using axe-core
axe-core, developed by Deque Systems, is an accessibility testing tool for developers with the following features:
- Detects web page accessibility violations in detail
- Can be integrated with testing frameworks like Jest and Cypress
- Also available as a browser extension (axe DevTools)
1. Combination of Cypress + axe-core
You can also run accessibility tests in the E2E testing tool Cypress using cypress-axe.
Install cypress-axe
npm install --save-dev cypress-axe
Use axe-core in Cypress tests
describe("Accessibility check", () => {
it("Should have no detectable accessibility violations", () => {
cy.visit("https://example.com");
cy.injectAxe();
cy.checkA11y();
});
});
cy.injectAxe(): Loadsaxe-coreinto the page.cy.checkA11y(): Detects accessibility violations on the page.
Benefits
✅ Detects accessibility violations across the entire page
✅ Can be validated in a real browser environment
✅ Can also test keyboard operations and focus movement
2. Using Playwright + axe-core
In addition to Cypress, there is a way to use axe-core within E2E tests using Playwright.
Install Playwright + axe-core
npm install --save-dev @playwright/test @axe-core/playwright
Use axe-core in Playwright tests
import { test, expect } from "@playwright/test";
import { injectAxe, checkA11y } from "@axe-core/playwright";
test("Page should be accessible", async ({ page }) => {
await page.goto("https://example.com");
await injectAxe(page);
await checkA11y(page);
});
Differentiating Lighthouse and axe-core
| Tool | Purpose/Features |
|---|---|
| Lighthouse | Excels at calculating accessibility scores and generating reports. Suitable for grasping overall areas for improvement. |
| axe-core | Detects accessibility violations in detail and is suitable for automated testing with Jest and Cypress. |
Establishing Accessibility Evaluation Criteria (Criteria Development Based on WCAG Guidelines)
Web accessibility evaluation criteria are formulated based on WCAG (Web Content Accessibility Guidelines). WCAG is an international guideline to ensure that all users can access web content, and it is primarily based on four principles.
The Four Principles of WCAG
1. Perceivable
Users must be able to perceive content through sight, hearing, touch, etc.
- Examples
- Set alternative text (alt attribute) for images.
- Provide captions or transcripts for videos and audio.
- Ensure sufficient contrast ratio (e.g., text-to-background color contrast ratio of 4.5:1 or higher).
- Mark up content so that screen readers can read information correctly.
2. Operable
All users must be able to operate the content.
- Examples
- Support keyboard operation (usable without a mouse).
- Set focus management appropriately (clear navigation with the tab key).
- Provide sufficient time for time-limited operations (allow enough time for automatic logouts or pop-ups).
- Suppress flashing or strong animations (to avoid triggering photosensitive seizures).
3. Understandable
Users must be able to understand the content.
- Examples
- Use concise and easy-to-understand language.
- Clearly communicate form error messages (e.g., "Please enter a valid email address" instead of "Input is required").
- Maintain navigation consistency (avoid different layouts for each page).
4. Robust
Content must be compatible with assistive technologies and usable in the future.
- Examples
- Use appropriate HTML markup (proper use of heading tags h1-h6, utilization of ARIA attributes).
- Support the latest web technologies (e.g., basic operations possible even without JavaScript).
- Conduct tests with multiple assistive technologies (screen readers, voice input software, etc.).
Benefits for Companies Establishing Accessibility Evaluation Criteria
- Improved User Experience (UX)
Improving accessibility makes it more comfortable for more people to use. - Compliance with Laws and Regulations
Japan: Provision of reasonable accommodation based on the "Act on the Elimination of Discrimination against Persons with Disabilities".
EU: Compliance with the "European Accessibility Act (EAA)".
America: Standards such as "ADA (Americans with Disabilities Act)" and "Section 508". - Impact on SEO (Search Engine Optimization)
Proper HTML structure and alt text settings also have a positive impact on SEO. - Corporate Social Responsibility (CSR)
Inclusive design contributes to enhancing a company's brand value.
Steps for Establishing Internal Evaluation Criteria
1. Determine the WCAG Conformance Level
WCAG has three conformance levels: A, AA, and AAA.
- A (Minimum Standard): Meets minimum accessibility requirements (e.g., alt text for images).
- AA (Recommended Standard): Criteria usable by many users (e.g., ensuring color contrast ratio).
- AAA (Advanced Standard): Ensures a high level of accessibility (e.g., providing sign language translation).
2. Document Evaluation Criteria Suitable for Your Products
- Develop criteria tailored to your company's operations and target users.
- Create an evaluation criteria document and share it with relevant stakeholders within the company.
Example) Documenting Evaluation Criteria
| Item | Description | Conformance Level |
|---|---|---|
| Image alt attribute | Set appropriate alt text for all images | A |
| Keyboard operation | All UI elements must be operable with a keyboard | AA |
| Color contrast ratio | 4.5:1 or higher (text and background) | AA |
| Form labels | Provide clear labels for input fields | AA |
| Video captions | Provide captions for all videos | AAA |
3. Conduct Regular Evaluations with a Combination of Automated and Manual Tests
- Automated Tests
- Regularly scan using tools like Axe, Lighthouse, and WAVE.
- Manual Tests
- Verify operation using only the keyboard.
- Validate with screen readers (NVDA, VoiceOver, JAWS).
- Usability testing (evaluation by actual users).
4. Document Audit Results and Establish an Improvement Cycle
- Create an audit report to clearly identify issues and improvement measures.
- Develop an improvement plan and review it regularly (e.g., quarterly accessibility review).
Keyboard Operation Check (Confirming All Functions are Operable with a Keyboard)
Checking keyboard operation is essential for improving accessibility (A11Y). Especially for users who cannot use a mouse or who use screen readers, it is required that all functions can be used with only the keyboard.
Keyboard Operation Check Points
1. Can all interactive elements be navigated with the Tab key?
- Pressing the
tabkey should move the focus to focusable elements such as buttons, links, and input fields on the page. - Also check if
Shift + Tabcan move in reverse order. - Elements with tabindex="-1" are not focusable, so set tabindex="0" if necessary.
2. Can buttons be pressed with Enter / Space?
- Confirm that buttons (
<button>,<a href>,<input type="submit">) can be activated with Enter or Space. - If
divorspanare used instead of buttons, simply addingrole="button"is not enough. You need to handleEnterandSpacein thekeydownevent.
3. Can modals be closed with the Escape key?
- Confirm that modal windows close when
Escapeis pressed while they are open. - Check if
aria-hiddenandaria-modal="true"settings are appropriate.
4. Is the focus indicator (outline) displayed correctly?
- Check that
outline: noneis not specified (it's important to ensure visibility, not just appearance). - When applying custom focus styles,
:focus-visiblecan be used to hide them during mouse operations.
button:focus-visible {
outline: 2px solid #005fcc; /* Accessible focus color */
border-radius: 4px;
}
Manual Testing
Use the tab key to check focus movement.
Automated Testing
Cypress is a useful tool for E2E testing and can also test keyboard operations.
describe('Keyboard Navigation Test', () => {
it('should allow navigation via Tab key', () => {
cy.visit('https://example.com');
cy.get('button').first().focus().should('have.css', 'outline');
cy.tab().should('have.focus'); // Move to the next element with Tab key
});
it('should close modal on Escape key press', () => {
cy.get('#open-modal').click();
cy.get('#modal').should('be.visible');
cy.get('body').type('{esc}');
cy.get('#modal').should('not.exist');
});
});
Playwright can test detailed keyboard operations using keyboard.press().
import { test, expect } from '@playwright/test';
test('Keyboard navigation works correctly', async ({ page }) => {
await page.goto('https://example.com');
// Focus button with Tab key
await page.keyboard.press('Tab');
await expect(page.locator('button')).toBeFocused();
// Click with Enter key and modal appears
await page.keyboard.press('Enter');
await expect(page.locator('#modal')).toBeVisible();
// Close modal with Escape key
await page.keyboard.press('Escape');
await expect(page.locator('#modal')).not.toBeVisible();
});
Optimizing Color Contrast (Ensuring High Contrast for Color Blind and Visually Impaired Users)
Importance of Color Contrast
- It is necessary to create a site that is easy to read and distinguish for people with visual impairments or color vision deficiency (color blindness). If the contrast between text color and background color is insufficient, the text becomes difficult to discern.
- It is also effective for elderly people and those with reduced vision, allowing text information to be conveyed clearly and improving accessibility.
- WCAG (Web Content Accessibility Guidelines) 2.1 recommends adhering to specific contrast ratios to enhance text readability and distinguishability.
Such considerations form the foundation for creating a website that is "comfortable and easy to read for everyone." By understanding this value and diligently working on it, many users will be helped, and as a result, overall service satisfaction will also improve.
Recommended Contrast Ratios
- Normal text: Contrast ratio 4.5:1 or higher
- Large text (18px or larger, or 14px bold): Contrast ratio 3:1 or higher
"Contrast ratio" is a numerical representation of the difference in brightness between the background color and the foreground color (text color). The higher this ratio, the more clearly the difference between the two colors can be perceived, meaning it is easier to read.
Example)
- The contrast ratio between black text (#000000) and white background (#FFFFFF) is 21:1, which is the highest level.
- For gray text (#767676) and white background (#FFFFFF), the contrast ratio is lower, and in some cases, it may not meet the standard.
Testing Tools
-
Lighthouse
- An auditing tool built into Google Chrome's developer tools.
- If there are any color contrast issues, they will be displayed in the "Accessibility" section.
-
axe DevTools
- A browser extension provided by Deque Systems.
- Scans pages and automatically lists accessibility issues. It's easy to find contrast violations.
-
Contrast Checker
- Online tools such as "WebAIM’s Contrast Checker".
- Manually enter color codes to check the contrast ratio and pass/fail status.
- When communicating with designers, it becomes easier to suggest specific numbers like "This color has a contrast ratio of 4.2:1, so let's make it a little brighter."
Improving Screen Reader Support (Proper Setting of alt Attributes)
Setting appropriate alt attributes, especially for images (<img> tags), is indispensable for screen reader users. By following the rules below, you can improve accessibility.
Basic Rules for alt Attributes
1. Decorative Images (Visual decoration only)
alt=""(empty)- When combined with
role="presentation", screen readers completely ignore it. - Example: Icon as background decoration
<img src="decorative-icon.png" alt="" role="presentation">
2. Meaningful Images (Images intended to provide information)
- Set
altthat concisely describes the image content. - When combined with
role="presentation", screen readers completely ignore it. - Example: Product image
<img src="product.jpg" alt="Red sneakers">
3. Images within Links
- The alt text should describe the content of the link destination.
- Example: Company logo as a link
<a href="https://example.com"> <img src="logo.png" alt="Link to Example Company's homepage"> </a>
4. Images Containing Text
- Write the text within the image directly in the alt attribute.
- Example: Banner image
<img src="sale-banner.jpg" alt="20% off all items! Until this weekend">
5. Diagrams and Graphs
- The alt attribute should contain a summary, and detailed explanations should use
figcaptionorlongdesc. - Example: Graph
<figure> <img src="sales-chart.png" alt="Bar chart showing sales trends"> <figcaption>Sales trends from January to March 2024</figcaption> </figure>
Enhancing Accessibility with ARIA Attributes
In cases where alt attributes alone are insufficient, ARIA (aria-*) attributes can be used to ensure that screen readers convey information correctly.
aria-label / aria-labelledby
-
aria-label: Directly labels an element.<button aria-label="Open menu">☰</button> -
aria-labelledby: References another element to provide a label.<h2 id="section-title">Product List</h2> <section aria-labelledby="section-title"> <p>Introducing our latest product lineup.</p> </section>
aria-live (Live Regions)
aria-live (live regions) is an attribute that instructs screen readers to "notify the user when the content of this area changes."
When content on a web page changes dynamically, the visual change may be apparent, but screen readers are not notified.
Therefore, applying aria-live allows screen readers to be informed of the change.
<p id="status" aria-live="polite">There are no items in the cart.</p>
<button onclick="document.getElementById('status').textContent = 'Item added to cart!'">
Add to Cart
</button>
- When the page opens, the screen reader announces "There are no items in the cart."
- When the button is pressed, the content of
<p>changes to "Item added to cart!". - Due to
aria-live="polite", the screen reader announces "Item added to cart!" at an appropriate time.
Screen Reader Testing Methods
Testing with Screen Readers
- Windows: NVDA
- Mac: VoiceOver (Launch with
Command + F5) - iPhone / iPad: VoiceOver (
Settings > Accessibility > VoiceOver)
Testing points
- Is
altread aloud correctly? - Verify the behavior of
aria-label/aria-labelledby. - Is important information conveyed correctly with
aria-live?
Automated Testing Tools
Using axe-core can efficiently detect accessibility issues.
- Install the Chrome extension "
axe DevTools". - Open DevTools (
F12) and run "axe DevTools". - Detects images without
altand errors inaria-*attributes.
Introducing ARIA Landmarks
ARIA (Accessible Rich Internet Applications) landmarks play a crucial role in making the main sections of a web page recognizable to screen readers and assistive technologies. When set correctly, they enable visually impaired users to quickly grasp the page structure and efficiently access necessary information.
Types of Landmarks and How to Apply Them
In HTML5, many elements already implicitly have ARIA roles, but in some cases, explicitly specifying the role attribute can enhance the behavior of screen readers.
| Element | Default Role | Recommended Role | Description |
|---|---|---|---|
<header> |
banner (conditional) |
role="banner" |
Indicates the header for the entire site or a section. |
<nav> |
navigation |
role="navigation" |
Indicates a navigation menu. |
<main> |
main |
role="main" |
The main content area of the page. |
<aside> |
complementary |
role="complementary" |
Provides supplementary information (e.g., sidebar). |
<footer> |
contentinfo (conditional) |
role="contentinfo" |
Indicates the footer (e.g., copyright information). |
Points
<header>and<footer>are recommended to haverole="banner"orrole="contentinfo"only when used as the header/footer for the entire page. (Do not apply when used within a section.)<main>should appear only once on the page.- If multiple
<nav>elements are present, it is desirable to usearia-labelto distinguish which navigation they are.
Code Example
The following code correctly sets ARIA landmarks, creating a structure that is easily recognizable by screen readers.
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ARIAランドマークの詳細な例</title>
</head>
<body>
<!-- ヘッダー -->
<header role="banner">
<h1>サイトタイトル</h1>
</header>
<!-- グローバルナビゲーション -->
<nav role="navigation" aria-label="グローバルナビゲーション">
<ul>
<li><a href="#">ホーム</a></li>
<li><a href="#">製品情報</a></li>
<li><a href="#">サポート</a></li>
</ul>
</nav>
<div style="display: flex;">
<!-- メインコンテンツ -->
<main role="main">
<h2>主要コンテンツ</h2>
<p>このセクションには、ページの主要な情報が含まれます。</p>
</main>
<!-- 関連情報 -->
<aside role="complementary" aria-labelledby="related-info">
<h3 id="related-info">関連情報</h3>
<p>補助的な情報を提供します。</p>
</aside>
</div>
<!-- サブナビゲーション -->
<nav role="navigation" aria-label="サイドナビゲーション">
<ul>
<li><a href="#">利用ガイド</a></li>
<li><a href="#">FAQ</a></li>
</ul>
</nav>
<!-- フッター -->
<footer role="contentinfo">
<p>© 2025 会社名</p>
</footer>
</body>
</html>
Points
- Use
aria-labelledby="related-info"to clarify what the supplementary information within theasiderelates to. - Use
aria-label="グローバルナビゲーション"andaria-label="サイドナビゲーション"to distinguish the roles of navigation. - Adjust layout with
divto placemainandasideside-by-side.
Improving Form Accessibility
By properly associating form labels with input fields, you can design forms that are more user-friendly for visually impaired users who use screen readers and for users who operate with keyboards. This not only improves accessibility but also enhances the user experience.
Explicitly Associate label Elements
By associating a label element with an input element using the for attribute, screen readers will correctly read out each input field in the form.
<label for="username">ユーザー名</label>
<input type="text" id="username" name="username">
Points
- Match the value of the
label'sforattribute with theidof the correspondinginput. - Placing the
labelnext to theinputalso makes it visually clearer.
Benefits
- Screen readers will correctly announce "Username, input field."
- Clicking the
labelmoves focus to the associatedinput, making it easier to click.
Utilizing aria-labelledby
By using aria-labelledby, you can associate a single label with multiple input fields, or use it as an alternative when it's difficult to visually place a label.
<div>
<span id="email-label">メールアドレス</span>
<input type="email" id="email" aria-labelledby="email-label">
</div>
Points
- Specify the
idof the associated element as the value foraria-labelledby. - Effective in situations where a
labelelement cannot be used (e.g., buttons or complex form layouts).
Benefits
- Screen readers will read correctly even without a
label. - A single label can be associated with multiple fields.
Utilizing aria-describedby
When providing supplementary information, using aria-describedby allows you to convey the supplementary description of an input field to screen readers.
<input type="text" id="phone" aria-describedby="phone-desc">
<span id="phone-desc">ハイフンなしで入力してください。</span>
Points
- Specify the
idof the supplementary description as the value foraria-describedby. - Can add usage hints or error message explanations.
Benefits
- When the user focuses on the field, the screen reader reads the supplementary description.
- Also effective for conveying error messages.
Modal Window Operation Check
Properly managing modal windows can improve keyboard operation comfort and accessibility. This article details the importance of focus control and appropriate implementation methods.
Properly Manage Focus within Modals
- Initial Focus Movement
When a modal opens, move focus to an appropriate focusable element (such as a close button or an input field). - Preventing Focus on Background Content
While the modal is open, control focus so that pressing the tab key does not move focus to background elements. - Closing Modal with Esc Key
Allow users to close the modal by pressing the Esc key.
Code Example (React + TypeScript Modal)
import { useEffect, useRef } from "react";
interface ModalProps {
isOpen: boolean;
onClose: () => void;
}
const Modal: React.FC<ModalProps> = ({ isOpen, onClose }) => {
const modalRef = useRef<HTMLDivElement>(null);
const closeButtonRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
if (isOpen) {
// Set initial focus when modal opens
setTimeout(() => {
closeButtonRef.current?.focus();
}, 0);
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "Escape") {
onClose();
} else if (event.key === "Tab") {
// Loop focus
const focusableElements = modalRef.current?.querySelectorAll(
'a[href], button, textarea, input, select'
) as NodeListOf<HTMLElement>;
if (!focusableElements) return;
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
if (event.shiftKey) {
if (document.activeElement === firstElement) {
event.preventDefault();
lastElement.focus();
}
} else {
if (document.activeElement === lastElement) {
event.preventDefault();
firstElement.focus();
}
}
}
};
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div
ref={modalRef}
role="dialog"
aria-hidden={!isOpen}
aria-labelledby="modal-title"
className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"
>
<div className="bg-white p-6 rounded-lg shadow-lg w-96">
<h2 id="modal-title" className="text-lg font-bold mb-4">
モーダルタイトル
</h2>
<p className="mb-4">モーダルの内容をここに記述します。</p>
<button
ref={closeButtonRef}
onClick={onClose}
className="bg-red-500 text-white px-4 py-2 rounded"
>
閉じる
</button>
</div>
</div>
);
};
Questions about this article 📝
If you have any questions or feedback about the content, please feel free to contact us.
Go to inquiry formRelated Articles
Test Strategy in the Next.js App Router Era: Development Confidence Backed by Jest, RTL, and Playwright
2025/04/22Building a Mock Server for Frontend Development: A Practical Guide Using @graphql-tools/mock and Faker
2024/12/30End-to-end testing for Express + MongoDB apps using Supertest and Jest
2024/12/20CI/CD Strategies to Accelerate and Automate Your Development Flow: Leveraging Caching, Parallel Execution, and AI Reviews
2024/03/12