_legacy/frontend/web-accessibility/SKILL.md
Webアクセシビリティ対応ガイド。WCAG 2.1準拠、セマンティックHTML、ARIA属性、キーボード操作、スクリーンリーダー対応など、誰もが使えるWebアプリケーション構築のベストプラクティス。
npx skillsauth add gaku52/claude-code-skills web-accessibilityInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
このSkillは、Webアクセシビリティをカバーします:
このガイドで学べること: WCAG準拠方法、セマンティックHTML、ARIA属性、キーボード操作、アクセシビリティテスト 公式で確認すべきこと: 最新のWCAG基準、ブラウザサポート、支援技術の動向
WCAG 2.1 Guidelines - W3Cアクセシビリティガイドライン
WAI-ARIA Authoring Practices - ARIAパターンガイド
MDN Accessibility - MDNアクセシビリティガイド
Apple Accessibility - iOSアクセシビリティ
以下の完全ガイドで、実践的なアクセシビリティ実装を学べます:
26,000文字 | React 18.2.0+ | Next.js 14.0+
27,500文字 | WAI-ARIA 1.2 | React 18.2.0+
28,000文字 | axe-core 4.8.0+ | Playwright 1.40.0+
合計: 81,500文字 | 3ガイド
| レベル | 説明 | 要件 | |-------|------|------| | A | 最低限 | 基本的なアクセシビリティ | | AA | 推奨(法的要件の場合多い) | 中程度のアクセシビリティ | | AAA | 最高レベル | 高度なアクセシビリティ |
<!-- ❌ 悪い例 -->
<div onclick="navigate()">Home</div>
<div onclick="submit()">Submit</div>
<!-- ✅ 良い例 -->
<nav>
<a href="/">Home</a>
</nav>
<button type="submit">Submit</button>
<header>
<nav aria-label="Main navigation">
<!-- ナビゲーション -->
</nav>
</header>
<main>
<article>
<h1>Article Title</h1>
<section>
<h2>Section Title</h2>
<!-- コンテンツ -->
</section>
</article>
<aside>
<!-- サイドバー -->
</aside>
</main>
<footer>
<!-- フッター -->
</footer>
<!-- ✅ 良い例(階層的) -->
<h1>Page Title</h1>
<h2>Section 1</h2>
<h3>Subsection 1.1</h3>
<h2>Section 2</h2>
<!-- ❌ 悪い例(階層がスキップ) -->
<h1>Page Title</h1>
<h3>Section 1</h3> <!-- h2をスキップ -->
// アイコンボタン
<button aria-label="Close">
<XIcon />
</button>
// 複数ナビゲーション
<nav aria-label="Main navigation">
{/* ... */}
</nav>
<nav aria-label="Footer navigation">
{/* ... */}
</nav>
// aria-labelledby(既存の要素を参照)
<div role="dialog" aria-labelledby="dialog-title">
<h2 id="dialog-title">Confirmation</h2>
{/* ... */}
</div>
<input
type="email"
aria-describedby="email-help"
/>
<span id="email-help">
We'll never share your email.
</span>
// リアルタイム通知
<div aria-live="polite" aria-atomic="true">
{status}
</div>
// 緊急通知
<div aria-live="assertive">
{error}
</div>
// カスタムコンポーネント
<div role="button" tabIndex={0} onClick={handleClick} onKeyDown={handleKeyDown}>
Click me
</div>
// リスト
<ul role="list">
<li role="listitem">Item 1</li>
<li role="listitem">Item 2</li>
</ul>
// ✅ ネイティブ要素(自動的にフォーカス可能)
<button>Click</button>
<a href="/">Link</a>
<input type="text" />
// ✅ カスタム要素(tabIndexを追加)
<div
role="button"
tabIndex={0}
onClick={handleClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleClick()
}
}}
>
Custom Button
</div>
import { useEffect, useRef } from 'react'
function Modal({ onClose }: { onClose: () => void }) {
const modalRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
onClose()
}
// Tab キーでフォーカストラップ
if (e.key === 'Tab') {
const focusableElements = modalRef.current?.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
)
if (!focusableElements) return
const firstElement = focusableElements[0] as HTMLElement
const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement
if (e.shiftKey && document.activeElement === firstElement) {
lastElement.focus()
e.preventDefault()
} else if (!e.shiftKey && document.activeElement === lastElement) {
firstElement.focus()
e.preventDefault()
}
}
}
document.addEventListener('keydown', handleKeyDown)
return () => document.removeEventListener('keydown', handleKeyDown)
}, [onClose])
return (
<div
ref={modalRef}
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
>
<h2 id="modal-title">Modal Title</h2>
<button onClick={onClose}>Close</button>
</div>
)
}
// app/layout.tsx
export default function RootLayout({ children }) {
return (
<html>
<body>
<a href="#main" className="skip-link">
Skip to main content
</a>
<nav>{/* ナビゲーション */}</nav>
<main id="main">{children}</main>
</body>
</html>
)
}
// globals.css
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
/* ❌ 悪い例(コントラスト不足) */
.text {
color: #999; /* 3:1 */
background: #fff;
}
/* ✅ 良い例 */
.text {
color: #666; /* 5.74:1 */
background: #fff;
}
/* ✅ 視認性の高いフォーカススタイル */
button:focus-visible {
outline: 3px solid #0066cc;
outline-offset: 2px;
}
/* ❌ 悪い例 */
button:focus {
outline: none; /* フォーカスが見えない */
}
interface ButtonProps {
children: React.ReactNode
onClick: () => void
disabled?: boolean
'aria-label'?: string
}
export function Button({ children, onClick, disabled, 'aria-label': ariaLabel }: ButtonProps) {
return (
<button
onClick={onClick}
disabled={disabled}
aria-label={ariaLabel}
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
>
{children}
</button>
)
}
export function ContactForm() {
return (
<form>
<div>
<label htmlFor="name">Name *</label>
<input
id="name"
type="text"
required
aria-required="true"
/>
</div>
<div>
<label htmlFor="email">Email *</label>
<input
id="email"
type="email"
required
aria-required="true"
aria-describedby="email-help"
/>
<span id="email-help" className="text-sm text-gray-600">
We'll never share your email.
</span>
</div>
<div role="group" aria-labelledby="contact-method">
<span id="contact-method">Preferred contact method</span>
<label>
<input type="radio" name="contact" value="email" />
Email
</label>
<label>
<input type="radio" name="contact" value="phone" />
Phone
</label>
</div>
<button type="submit">Submit</button>
</form>
)
}
'use client'
import { useEffect, useRef } from 'react'
import { createPortal } from 'react-dom'
interface ModalProps {
isOpen: boolean
onClose: () => void
title: string
children: React.ReactNode
}
export function Modal({ isOpen, onClose, title, children }: ModalProps) {
const modalRef = useRef<HTMLDivElement>(null)
const previousActiveElement = useRef<HTMLElement | null>(null)
useEffect(() => {
if (isOpen) {
previousActiveElement.current = document.activeElement as HTMLElement
modalRef.current?.focus()
} else {
previousActiveElement.current?.focus()
}
}, [isOpen])
if (!isOpen) return null
return createPortal(
<div
className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center"
onClick={onClose}
>
<div
ref={modalRef}
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
tabIndex={-1}
className="bg-white p-6 rounded-lg max-w-md w-full"
onClick={(e) => e.stopPropagation()}
>
<h2 id="modal-title" className="text-2xl font-bold mb-4">
{title}
</h2>
{children}
<button
onClick={onClose}
aria-label="Close modal"
className="mt-4 px-4 py-2 bg-gray-200 rounded"
>
Close
</button>
</div>
</div>,
document.body
)
}
pnpm add -D @axe-core/react
// app/layout.tsx(開発環境のみ)
if (process.env.NODE_ENV !== 'production') {
const axe = require('@axe-core/react')
const React = require('react')
const ReactDOM = require('react-dom')
axe(React, ReactDOM, 1000)
}
アクセシビリティ監査
このページのアクセシビリティを確認してください。
WCAG AA基準に準拠しているか確認してください。
ARIA属性追加
このコンポーネントに適切なARIA属性を追加してください。
スクリーンリーダーで読み上げられるようにしてください。
Last updated: 2025-12-26
tools
Fundamentals of modern web development. Framework selection (React, Vue, Next.js), project architecture, state management, routing, build tools, and CSS strategy best practices.
development
# React Development — Complete Guide > A comprehensive guide to building modern React applications with TypeScript. Covers fundamentals through advanced patterns, Hooks mastery, TypeScript integration, performance optimization, and algorithm internals. ## Target Audience - Developers new to React who want a solid foundation - Intermediate React developers looking to deepen their understanding of Hooks and TypeScript patterns - Engineers who want to understand React's internal algorithms (Virt
development
# Node.js Development Skill > A practical guide collection for Node.js development. Covers all aspects of Node.js application development, including Express, NestJS, asynchronous patterns, and performance optimization. ## Overview This skill covers the following topics: - **Express & NestJS**: When to use a lightweight framework vs. an enterprise framework - **Asynchronous Patterns**: Promise, async/await, Event Emitter, Streams, Worker Threads, Cluster - **Performance Optimization**: Memory
development
# Backend Development — Complete Guide > A comprehensive guide to backend engineering. Covers the fundamentals of HTTP, REST API design, databases, authentication, environment configuration, and algorithm proofs — everything needed to build robust server-side systems. ## Target Audience - Developers new to backend engineering - Frontend engineers expanding toward full-stack development - Engineers looking to solidify their understanding of server-side fundamentals ## Prerequisites - Basic p