- 74 brands: airbnb, stripe, apple, figma, linear, vercel, etc. - 147 files: DESIGN.md + README.md per brand (~2.1 MB) - Each DESIGN.md contains structured brand analysis (colors, typography, components) - Updated 00-overview.md with new design-systems directory
278 lines
10 KiB
Markdown
278 lines
10 KiB
Markdown
---
|
||
title: WCAG AA Practical Guide
|
||
created: 2026-06-02
|
||
updated: 2026-06-02
|
||
type: concept
|
||
tags: [web-design, accessibility]
|
||
sources:
|
||
- https://webaim.org/standards/wcag/checklist
|
||
- https://www.a11yproject.com/checklist/
|
||
- https://www.w3.org/WAI/standards-guidelines/wcag/
|
||
confidence: high
|
||
---
|
||
|
||
# WCAG AA Practical Guide — Доступность как точка отрыва
|
||
|
||
> **В РФ WCAG AA не соблюдает НИКТО из коммерческих сайтов.**
|
||
> Это наш главный разрыв с конкурентами — юридический хедж, SEO-буст, репутация.
|
||
>
|
||
> *Стандарт: WCAG 2.2 Level AA (86 критериев). Для типового сайта достаточно AA.*
|
||
|
||
---
|
||
|
||
## Чек-лист WCAG AA для разработчика Astro
|
||
|
||
### Perceivable (Воспринимаемое)
|
||
|
||
#### ✅ 1.1.1 Non-text Content (A)
|
||
**Что:** все изображения имеют alt-текст.
|
||
**Как в Astro:**
|
||
```astro
|
||
<img src="/team.jpg" alt="Команда агентства: 5 человек в офисе" />
|
||
<!-- Декоративные: -->
|
||
<img src="/bg-pattern.png" alt="" aria-hidden="true" />
|
||
<!-- Или CSS background -->
|
||
```
|
||
**Проверка:** в браузере удалить стили — вся информация должна быть доступна.
|
||
|
||
#### ✅ 1.3.1 Info and Relationships (A)
|
||
**Что:** семантический HTML5. Заголовки H1→H2→H3. Таблицы с th. Формы с label.
|
||
**Как в Astro:**
|
||
```astro
|
||
<header> <nav> <main> <section> <article> <aside> <footer>
|
||
|
||
<!-- Формы -->
|
||
<label for="name">Ваше имя</label>
|
||
<input id="name" type="text" autocomplete="name" />
|
||
|
||
<!-- Заголовки строго по иерархии -->
|
||
<h1>Услуги</h1>
|
||
<h2>Ремонт квартир</h2>
|
||
<h3>Косметический ремонт</h3>
|
||
```
|
||
|
||
#### ✅ 1.4.3 Contrast (Minimum) (AA)
|
||
**Что:**
|
||
- Текст <18px: контраст **≥4.5:1**
|
||
- Текст ≥18px (или ≥14px bold): контраст **≥3:1**
|
||
**Инструмент:** WebAIM Contrast Checker, axe DevTools, Lighthouse
|
||
**Как в CSS:**
|
||
```css
|
||
/* Всегда проверять контраст! */
|
||
--color-text: #1A1A1A; /* на белом #FFF → 15:1 ✓ */
|
||
--color-text-secondary: #666; /* на белом #FFF → 5.4:1 ✓ */
|
||
--color-text-muted: #999; /* на белом #FFF → 2.8:1 ✗ ТОЛЬКО для декора */
|
||
```
|
||
|
||
#### ✅ 1.4.11 Non-text Contrast (AA)
|
||
**Что:** иконки, кнопки, границы, focus indicators — контраст **≥3:1** с фоном.
|
||
**Критично для:** кнопок CTA, иконок соцсетей, чекбоксов, переключателей.
|
||
```css
|
||
/* Кнопка: текст + фон должны иметь 3:1 между собой */
|
||
.btn-primary {
|
||
background: #0066CC; /* синий */
|
||
color: #FFFFFF; /* белый — контраст с фоном >3:1 ✓ */
|
||
}
|
||
/* Focus indicator */
|
||
*:focus-visible {
|
||
outline: 3px solid #0066CC;
|
||
outline-offset: 2px;
|
||
}
|
||
```
|
||
|
||
#### ✅ 1.4.10 Reflow (AA)
|
||
**Что:** при ширине 320px (1280px + 400% zoom) контент не обрезается и не требует горизонтального скролла.
|
||
**Это означает:** responsive design обязателен. Container queries + media queries.
|
||
**Проверка:** Chrome DevTools → Ctrl+Shift+M → 320px ширина.
|
||
|
||
#### ✅ 1.4.12 Text Spacing (AA)
|
||
**Что:** при переопределении пользователем межстрочного интервала (1.5×), межбуквенного (0.12×), межсловного (0.16×) контент не теряется.
|
||
**Как избежать:**
|
||
```css
|
||
/* ПЛОХО: фиксированная высота */
|
||
.card { height: 300px; overflow: hidden; }
|
||
|
||
/* ХОРОШО: без фиксации высоты */
|
||
.card { min-height: 0; }
|
||
```
|
||
|
||
---
|
||
|
||
### Operable (Управляемое)
|
||
|
||
#### ✅ 2.1.1 Keyboard (A)
|
||
**Что:** все интерактивные элементы доступны с клавиатуры (Tab, Enter, Space, Escape).
|
||
**Как проверить:** пройти Tab'ом по всей странице. Должны быть доступны: ссылки, кнопки, формы, меню, модалки.
|
||
```astro
|
||
<!-- Всегда используйте <button>, не <div onclick -->
|
||
<button type="button">Отправить</button>
|
||
<a href="/uslugi/">Наши услуги</a>
|
||
```
|
||
|
||
#### ✅ 2.4.1 Bypass Blocks (A)
|
||
**Что:** ссылка «Перейти к содержимому» (skip link).
|
||
```html
|
||
<!-- Первая ссылка на странице: -->
|
||
<a href="#main-content" class="skip-link">Перейти к содержимому</a>
|
||
|
||
<style>
|
||
.skip-link {
|
||
position: absolute;
|
||
top: -40px; /* скрыт, пока не в фокусе */
|
||
left: 0;
|
||
z-index: 100;
|
||
}
|
||
.skip-link:focus {
|
||
top: 0; /* появляется при Tab */
|
||
background: #0066CC;
|
||
color: white;
|
||
padding: 8px 16px;
|
||
}
|
||
</style>
|
||
```
|
||
|
||
#### ✅ 2.4.5 Multiple Ways (AA)
|
||
**Что:** как минимум 2 способа найти любую страницу на сайте.
|
||
```html
|
||
<!-- Вариант 1: основная навигация -->
|
||
<nav>...</nav>
|
||
<!-- Вариант 2: поиск -->
|
||
<form role="search">...</form>
|
||
<!-- Вариант 3: sitemap.xml (технически) -->
|
||
```
|
||
|
||
#### ✅ 2.4.7 Focus Visible (AA)
|
||
**Что:** при Tab все элементы показывают видимый фокус.
|
||
```css
|
||
/* Современный стандарт (Chrome 122+, Firefox 131+, Safari 17.4+): */
|
||
*:focus-visible {
|
||
outline: 3px solid var(--color-accent);
|
||
outline-offset: 2px;
|
||
border-radius: 4px;
|
||
}
|
||
/* Убираем только для мыши */
|
||
*:focus:not(:focus-visible) {
|
||
outline: none;
|
||
}
|
||
```
|
||
|
||
#### ✅ 2.4.11 Focus Not Obscured (AA — новый в WCAG 2.2)
|
||
**Что:** при фокусе элемент не должен быть полностью скрыт (например, под sticky header).
|
||
**Решение:** при Tab к элементу под sticky header — скролл до него с отступом.
|
||
```css
|
||
/* scroll-padding-top в :root */
|
||
:root {
|
||
scroll-padding-top: 80px; /* высота sticky header + запас */
|
||
}
|
||
```
|
||
|
||
#### ✅ 2.2.2 Pause, Stop, Hide (A)
|
||
**Что:** авто-анимации >5 сек должны иметь кнопку паузы.
|
||
**Касается:** каруселей, бегущих строк, авто-обновления.
|
||
|
||
---
|
||
|
||
### Understandable (Понятное)
|
||
|
||
#### ✅ 3.2.3 Consistent Navigation (AA)
|
||
**Что:** навигация одинакова на всех страницах. Порядок пунктов не меняется.
|
||
**В Astro:** один компонент Nav на всех страницах.
|
||
|
||
#### ✅ 3.3.2 Labels or Instructions (A)
|
||
**Что:** у каждого поля формы есть label или aria-label.
|
||
```astro
|
||
<label for="phone">Номер телефона</label>
|
||
<input id="phone" type="tel" autocomplete="tel" required />
|
||
|
||
<!-- Или aria-label для иконочных кнопок -->
|
||
<button aria-label="Поиск">
|
||
<svg><!-- иконка лупы --></svg>
|
||
</button>
|
||
```
|
||
|
||
#### ✅ 3.3.4 Error Prevention (AA)
|
||
**Что:** при финансовых/юридических действиях — подтверждение перед отправкой.
|
||
```astro
|
||
<button type="submit" onclick="return confirm('Подтвердите оплату 5 000 ₽')">
|
||
Оплатить
|
||
</button>
|
||
```
|
||
|
||
---
|
||
|
||
### Robust (Надёжное)
|
||
|
||
#### ✅ 4.1.2 Name, Role, Value (A)
|
||
**Что:** все кастомные компоненты имеют правильные ARIA-атрибуты.
|
||
```astro
|
||
<div role="tablist">
|
||
<button role="tab" aria-selected="true">Услуги</button>
|
||
<button role="tab" aria-selected="false">Цены</button>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## 🛠 Инструменты проверки (бесплатные)
|
||
|
||
| Инструмент | Что проверяет | Как использовать |
|
||
|-----------|--------------|-----------------|
|
||
| **axe DevTools** (браузер) | 50+ критериев WCAG | Chrome → F12 → axe → Scan ALL |
|
||
| **Lighthouse** | 20+ критериев | Chrome → F12 → Lighthouse → Accessibility |
|
||
| **WAVE** (wave.webaim.org) | Контраст, alt, структура | Расширение Chrome |
|
||
| **WebAIM Contrast Checker** | Контраст цветов | https://webaim.org/resources/contrastchecker/ |
|
||
| **Tab test** | Клавиатура | Tab по всей странице вручную |
|
||
| **Screen reader test** | Озвучка | Включить VoiceOver (Mac) / NVDA (Win) |
|
||
|
||
---
|
||
|
||
## Минимальный WCAG AA для Astro-шаблона (10 минут)
|
||
|
||
```css
|
||
/* 1. Контраст */
|
||
:root {
|
||
--color-text: #1A1A1A; /* на белом: 15:1 ✓ */
|
||
--color-text-secondary: #595959; /* на белом: 7:1 ✓ */
|
||
}
|
||
|
||
/* 2. Focus */
|
||
*:focus-visible {
|
||
outline: 3px solid #0066CC;
|
||
outline-offset: 2px;
|
||
}
|
||
:root { scroll-padding-top: 80px; }
|
||
|
||
/* 3. Skip link */
|
||
.skip-link { position: absolute; top: -40px; }
|
||
.skip-link:focus { top: 0; }
|
||
```
|
||
|
||
```astro
|
||
<!-- 4. Alt-тексты на все <img> -->
|
||
<img src="..." alt="Описание" />
|
||
|
||
<!-- 5. Skip link первой строкой в <body> -->
|
||
<a href="#main" class="skip-link">Перейти к содержимому</a>
|
||
|
||
<!-- 6. Semantic HTML -->
|
||
<header> <nav> <main id="main"> <footer>
|
||
|
||
<!-- 7. Labels для форм -->
|
||
<label for="name">Имя</label>
|
||
<input id="name" type="text" />
|
||
```
|
||
|
||
**Результат:** 80% WCAG AA за 10 минут. Остальное — точечно под тип контента.
|
||
|
||
---
|
||
|
||
## Почему это даёт отрыв в РФ
|
||
|
||
| Фактор | Эффект |
|
||
|--------|--------|
|
||
| **Юридический хедж** | Законы об accessible web обсуждаются в ГД. Через 2-3 года станут обязательными |
|
||
| **SEO-буст** | Яндекс учитывает семантический HTML, alt-тексты, скорость |
|
||
| **Конверсия** | То что помогает инвалидам — помогает всем (Crawford) |
|
||
| **Репутация** | Первый accessible-сайт в нише = пресса, кейсы, награды |
|
||
| **WCAG 2.2** | 9 новых критериев (focus visible, focus not obscured, accessible name) |
|