Files
wow-design-wiki/concepts/wcag-aa-practical-guide.md

278 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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) |