Доступность: сайт для всех
Навигация с клавиатуры, видимый фокус, контраст, alt и порядок заголовков, skip-link и первые aria-атрибуты.
Что ты научишься делать
- Пройдёшь свою страницу целиком одной клавишей Tab и увидишь, где фокус теряется
- Проверишь контраст текста и поймёшь, какой считается достаточным
- Добавишь skip-link и подписи там, где текста не хватает
#Кто такие «все»
Доступность — это не про «особую версию сайта для инвалидов». Это про то, чтобы обычный сайт работал у всех.
- Человек не видит экран и слушает страницу голосовой программой.
- У человека сломана мышь, или он просто быстрее работает с клавиатуры.
- Человек плохо различает цвета — а у тебя ошибка помечена только красным.
- Человек читает с телефона на солнце, и светло-серый текст не виден вообще.
- У человека сегодня одна рука занята ребёнком.
Почти всё, что нужно для доступности, ты уже делал: семантика, alt, label, порядок заголовков. Осталось собрать это вместе и проверить.
#Проверка номер один: клавиша Tab
Убери руку с мыши и пройди свою страницу клавишей Tab. Фокус должен переходить по ссылкам, полям и кнопкам сверху вниз, и всегда быть видимым.
Если фокус пропал — значит, где-то стоит outline: none без замены. Это самая частая и самая обидная ошибка: человек нажимает Tab и не понимает, где находится.
Так не надо
a:focus,
button:focus {
outline: none;
}Обводку убрали, потому что «некрасиво». Пользоваться клавиатурой стало невозможно: положение фокуса больше не видно.
Так надо
a:focus-visible,
button:focus-visible {
outline: 2px solid #6544e0;
outline-offset: 3px;
}Своя обводка вместо стандартной. <code>:focus-visible</code> показывает её при работе с клавиатуры и не мешает при клике мышью.
#Порядок фокуса задаёт разметка
Браузер обходит элементы в том порядке, в котором они написаны в HTML. Если CSS переставил блоки местами визуально, фокус всё равно пойдёт по исходному порядку — и человек будет прыгать по странице непонятно как.
Вывод простой: пиши разметку в логическом порядке чтения, а переставляй только оформлением, и то осторожно.
#Skip-link: пропустить меню
В шапке двадцать ссылок. Человек, который ходит по странице клавиатурой, вынужден прожимать их все на каждой странице, прежде чем добраться до текста.
Решение — skip-link: первая ссылка в документе, ведущая прямо к содержимому. Обычно она спрятана и появляется только при получении фокуса.
<a class="skip-link" href="#main">Перейти к содержанию</a><header>…меню…</header><main id="main">…</main>.skip-link { position: fixed; top: 12px; left: 12px; padding: 10px 18px; background: #fff; border-radius: 999px; /* Уводим за верхний край, пока фокуса нет */ transform: translateY(-200%); transition: transform .3s;}.skip-link:focus { transform: translateY(0);}#Контраст
Светло-серый текст на белом фоне выглядит «стильно» ровно до первого солнечного дня. Стандарт WCAG задаёт минимальную разницу яркости между текстом и фоном — 4.5 : 1 для обычного текста и 3 : 1 для крупного (от 24 px или от 19 px жирного).
Это не вкусовщина, а измеримая величина: её считают по формуле и проверяют инструментами. В следующем модуле мы соберём для этого отдельную лабораторию цвета.
#Когда текста не хватает: aria-label
Кнопка с одной иконкой — крестик, лупа, стрелка — визуально понятна, но голосовая программа прочитает пустоту. Для таких случаев есть aria-label: невидимая подпись специально для вспомогательных технологий.
<button type="button" aria-label="Закрыть окно"> <svg width="20" height="20" aria-hidden="true">…</svg></button>aria-hidden="true" на иконке говорит: «этот кусок читать не надо, он декоративный». Иначе программа может попытаться озвучить содержимое svg.
Ещё два атрибута, которые пригодятся уже сейчас:
aria-expanded="true|false"— на кнопке, которая что-то раскрывает: меню, аккордеон.aria-current="page"— на ссылке текущей страницы в меню.
#Короткий чек-лист на каждый день
Пройди страницу клавишей Tab
Фокус виден всегда, порядок логичный, ничего не пропускается и не «залипает».
Отключи стили
Страница читается сверху вниз как осмысленный документ? Значит, структура в порядке.
Проверь заголовки
Один
h1, уровни идут подряд, по заголовкам можно составить оглавление.Проверь картинки и кнопки
У каждой картинки —
alt, у каждой иконки-кнопки —aria-label.Проверь контраст
Основной текст — не меньше 4.5 : 1. Особенно смотри на подписи и подсказки: их часто делают слишком светлыми.
Увеличь масштаб до 200 %
Нажми Ctrl++ несколько раз. Текст должен переноситься, а не обрезаться.
Где спотыкаются почти все
outline: none без замены
Почему Человек с клавиатурой перестаёт понимать, где находится. Это полностью ломает навигацию.
Как надо Убираешь стандартную обводку — рисуй свою через :focus-visible. Заметную, а не «еле-еле».
Кнопка сделана из div со скриптом
Почему До неё не добраться клавишей Tab, она не нажимается пробелом, голосовая программа не назовёт её кнопкой.
Как надо Действие — <button>, переход — <a href>. Оба уже доступны из коробки.
Ошибка формы показана только красной рамкой
Почему Люди, которые не различают красный, не увидят разницы. Голосовая программа тем более не увидит цвет.
Как надо Добавь текст ошибки рядом с полем и опиши, что именно исправить.
aria-label на всём подряд
Почему aria-label заменяет собой текст элемента. Повесив его на ссылку с текстом, ты просто скроешь настоящий текст от голосовой программы.
Как надо Ставь aria-label только там, где видимого текста нет: иконки, кнопки-крестики.
- Доступность accessibility, a11y
- Свойство сайта быть пригодным для всех, включая людей с ограничениями зрения, слуха и моторики.
- Программа чтения с экрана screen reader
- Приложение, озвучивающее содержимое экрана: VoiceOver, NVDA, JAWS, TalkBack.
- Фокус focus
- Элемент, на котором сейчас находится клавиатура. Его положение обязано быть видимым.
- Skip-link skip link
- Первая ссылка страницы, позволяющая перепрыгнуть меню и попасть сразу к содержимому.
- Контраст contrast ratio
- Отношение яркости текста к яркости фона. Минимум 4.5 : 1 для обычного текста.
- ARIA ARIA
- Набор атрибутов, сообщающих вспомогательным технологиям роль и состояние элемента.
Проверь себя
Убирать обводку можно только вместе с добавлением своей. Иначе навигация с клавиатуры становится слепой.
4.5 : 1 для обычного текста, 3 : 1 — для крупного (от 24 px или 19 px жирного).
Без него приходится прожимать Tab по всем ссылкам шапки на каждой странице.
<code>aria-label</code> заменяет текст элемента. Если текст есть, атрибут его просто перекроет и спрячет.
Верных вариантов несколько.
Положительный <code>tabindex</code> ломает естественный порядок обхода — это как раз ухудшение.
Задание
Сделать форму доступной
Перед тобой форма из восьмого урока, из которой убрали всё, что делало её доступной. Верни: подписи label со связкой for/id, осмысленный alt картинке, aria-label кнопке с иконкой и видимую обводку фокуса в CSS.
Подсказка 1
Подпись ставится перед полем: <label for="name">Имя</label>. Значение for должно совпадать с id поля.
Подсказка 2
В CSS замени блок :focus { outline: none; } на :focus-visible { outline: 3px solid #6544e0; outline-offset: 2px; }
Показать решение
<h1>Запись</h1><form> <label for="name">Имя</label> <input type="text" id="name" name="name" placeholder="Марина"> <label for="mail">Почта</label> <input type="email" id="mail" name="mail" placeholder="hi@polka.ru"> <button type="button" class="icon-btn" aria-label="Очистить форму"> <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true"> <path d="m6 6 12 12M18 6 6 18" stroke="currentColor" stroke-width="2"/> </svg> </button> <button type="submit">Записаться</button></form>label { display: block; margin-bottom: 4px; font-weight: 600;}input, button { padding: 8px 12px; font: inherit;}:focus-visible { outline: 3px solid #6544e0; outline-offset: 2px;}