10 Модуль 2 Смысл и структура 15 мин урок 10 из 25

Доступность: сайт для всех

Навигация с клавиатуры, видимый фокус, контраст, 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> показывает её при работе с клавиатуры и не мешает при клике мышью.

Нажми Tab внутри примера и посмотри на обводку
В песочницу

#Порядок фокуса задаёт разметка

Браузер обходит элементы в том порядке, в котором они написаны в HTML. Если CSS переставил блоки местами визуально, фокус всё равно пойдёт по исходному порядку — и человек будет прыгать по странице непонятно как.

Вывод простой: пиши разметку в логическом порядке чтения, а переставляй только оформлением, и то осторожно.

В шапке двадцать ссылок. Человек, который ходит по странице клавиатурой, вынужден прожимать их все на каждой странице, прежде чем добраться до текста.

Решение — skip-link: первая ссылка в документе, ведущая прямо к содержимому. Обычно она спрятана и появляется только при получении фокуса.

HTMLПервая строка в body
<a class="skip-link" href="#main">Перейти к содержанию</a><header>…меню…</header><main id="main"></main>
CSSstyle.css
.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: невидимая подпись специально для вспомогательных технологий.

HTMLИконка с подписью
<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" — на ссылке текущей страницы в меню.

Проверка доступности

Разбирает демо-код и говорит, что мешает читать страницу с клавиатуры и через скринридер.

Что проверяемПравило
Альтернативы у картинокУ каждой img есть осмысленный alt
Иерархия заголовковПосле h1 идёт h2, а не h4
КонтрастТекст к фону — минимум 4.5 : 1
КлавиатураДо каждой ссылки и кнопки можно дойти табом

#Короткий чек-лист на каждый день

  1. Пройди страницу клавишей Tab

    Фокус виден всегда, порядок логичный, ничего не пропускается и не «залипает».

  2. Отключи стили

    Страница читается сверху вниз как осмысленный документ? Значит, структура в порядке.

  3. Проверь заголовки

    Один h1, уровни идут подряд, по заголовкам можно составить оглавление.

  4. Проверь картинки и кнопки

    У каждой картинки — alt, у каждой иконки-кнопки — aria-label.

  5. Проверь контраст

    Основной текст — не меньше 4.5 : 1. Особенно смотри на подписи и подсказки: их часто делают слишком светлыми.

  6. Увеличь масштаб до 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
Набор атрибутов, сообщающих вспомогательным технологиям роль и состояние элемента.

Проверь себя

  1. Что не так с правилом <code>button:focus { outline: none; }</code>?

    Убирать обводку можно только вместе с добавлением своей. Иначе навигация с клавиатуры становится слепой.

  2. Какой минимальный контраст нужен обычному тексту по WCAG?

    4.5 : 1 для обычного текста, 3 : 1 — для крупного (от 24 px или 19 px жирного).

  3. Зачем нужен skip-link?

    Без него приходится прожимать Tab по всем ссылкам шапки на каждой странице.

  4. Когда нужен aria-label?

    <code>aria-label</code> заменяет текст элемента. Если текст есть, атрибут его просто перекроет и спрячет.

  5. Что из перечисленного улучшает доступность?

    Верных вариантов несколько.

    Положительный <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; }

    Показать решение
    HTMLindex.html
    <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>
    CSSstyle.css
    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;}

    Проверь себя