Html5 семантика и доступность (a11y): чек-лист для верстальщика

Чтобы совместить HTML5 семантику и доступность сайта a11y, размечайте страницу смысловыми блоками (header/nav/main/section/article/footer), держите последовательную иерархию заголовков, подписывайте поля форм через label, давайте текстовые альтернативы медиа и применяйте ARIA только там, где нативной семантики недостаточно. Ниже - чек-лист и безопасные шаги для правок.

Короткий чек-лист для быстрой проверки семантики и a11y

  • Есть один <main> на страницу; навигация в <nav>, шапка/подвал - в <header>/<footer>.
  • Заголовки идут без пропусков уровней; структура читается скринридером и по оглавлению/outline.
  • У всех полей форм есть и понятные сообщения об ошибках; обязательность и формат ввода обозначены.
  • У изображений есть корректный alt; у видео - субтитры/транскрипт по необходимости; фокус клавиатуры всегда виден.
  • ARIA не дублирует нативные роли; нет role на интерактивных элементах без причины.
  • Быстрый прогон: клавиатура (Tab/Shift+Tab/Enter/Escape) + авто-проверка (Lighthouse/axe) + ручная проверка заголовков и форм.

Структурные элементы: когда и как применять section, article, nav, header, footer

Семантическая верстка HTML5 нужна, когда вы хотите, чтобы документ был понятен не только визуально, но и по структуре: для скринридеров, поисковых роботов, автоматических тестов и поддержки. Используйте HTML5 семантические теги, если блок имеет роль в документе, а не просто нужен для сетки.

  • Когда подходит: страницы с повторяющимися зонами (шапка, меню, контент, сайдбар, подвал), статьи/карточки, списки публикаций, многоуровневая навигация.
  • Как применять:
    • <header> - вводная часть страницы/раздела (может встречаться внутри <article>).
    • <nav> - блок ссылок для навигации (главное меню, хлебные крошки, пагинация).
    • <main> - уникальный основной контент, один раз на страницу.
    • <section> - смысловой раздел с заголовком (обычно нужен <h2>...</h2> или ниже).
    • <article> - самодостаточная единица (пост, карточка новости, комментарий), которую можно вынести/процитировать.
    • <footer> - завершающая часть страницы/раздела (контакты, ссылки, юридическая информация).
  • Когда не стоит: не используйте <section> как замену <div> ради стилей; не делайте <nav> вокруг одиночной ссылки; не создавайте несколько <main>.

Текстовая семантика: заголовки, абзацы, списки и их роль в навигации

Для уверенной проверки структуры вам понадобятся: DevTools (Accessibility tree), автоматический анализатор (например, axe DevTools или Lighthouse) и базовое умение прогонять страницу только клавиатурой. Для ручной проверки полезны: просмотр Outline/структуры заголовков (расширение/инструмент) и любой скринридер (NVDA/VoiceOver) хотя бы на базовом уровне.

  • Заголовки: один логический <h1> (на странице он может быть визуально скрыт), дальше - последовательные уровни без "скачков" ради размера.
  • Абзацы: текстовые блоки - в <p>; не используйте <br> как разметку структуры.
  • Списки: группы однотипных элементов - в <ul>/<ol>; пункты меню/фич/шагов - только <li>.
  • Навигация по странице: при корректной семантике пользователь скринридера может прыгать по заголовкам и спискам, поэтому не "ломайте" структуру ради CSS.

Формы и управляющие элементы: метки, группы, валидация и aria-атрибуты

HTML5 семантика и доступность (a11y): чек-лист для верстальщика - иллюстрация
  1. Свяжите поля с метками. Для каждого элемента ввода используйте + id или оборачивайте элемент управления в ....

    • Fast-track: добавьте видимую подпись (например, Email) и id="email" прямо сейчас.
    • Deep-audit: проверьте, что "визуальная подпись" совпадает с доступным именем (Accessible Name) и нет дублирования через aria-label.
  2. Группируйте связанные поля. Используйте <fieldset> и <legend> для групп (например, способ доставки, диапазоны, набор чекбоксов).

    • Fast-track: оберните группу чекбоксов в <fieldset> и добавьте короткий <legend>.
    • Deep-audit: проверьте, что порядок Tab соответствует визуальному, а легенда не скрыта так, что становится недоступной скринридеру.
  3. Делайте ошибки понятными и связанными. Сообщение об ошибке должно быть текстом рядом с полем и программно связано через aria-describedby; статус обязательности передавайте нативно (required) и/или текстом.

    • Fast-track: добавьте блок <span id="email-error">Введите корректный email</span> и у поля aria-describedby="email-error".
    • Deep-audit: при отправке фокус переводите на первый ошибочный элемент и объявляйте общий статус (например, через role="alert" для сводки ошибок, если она есть).
  4. Используйте правильные типы и атрибуты. type="email", autocomplete, inputmode, min/max и pattern улучшают ввод и уменьшают ошибки.

    • Fast-track: проставьте autocomplete и корректные type для основных полей.
    • Deep-audit: проверьте, что валидация не завязана только на цвет и что подсказка формата есть до ошибки.
  5. Не подменяйте нативные элементы кастомом без нужды. Если делаете кастомные селекты/переключатели, обеспечьте полное управление с клавиатуры и корректные роли/состояния.

    • Fast-track: по возможности вернитесь к нативному <select>/.
    • Deep-audit: для кастома реализуйте управление стрелками, Escape, Enter, озвучивание состояния и корректный фокус-менеджмент.

Быстрый режим

  1. Проверьте: у каждого поля есть и уникальный id.
  2. Добавьте required и текстовую подсказку формата (не только цвет/иконку).
  3. Свяжите ошибки через aria-describedby и показывайте их рядом с полем.
  4. Проставьте autocomplete для типовых данных и корректные type.

Мультимедиа и интерактивные компоненты: доступные img, video, canvas и tabindex

  • У <img> есть уместный alt: описание смысла, а не внешнего вида; у декоративных - пустой alt="".
  • У кликабельных изображений понятное доступное имя (обычно через текст рядом или aria-label на ссылке/кнопке, если текста нет).
  • Видео/аудио: есть контролы, а при необходимости - субтитры/транскрипт (зависит от контента и аудитории).
  • <canvas>: есть альтернативный текст внутри тега или отдельное доступное представление результата (таблица/текст), если canvas несет информацию.
  • Фокус клавиатуры виден всегда; не убирайте outline без замены на заметный стиль.
  • Не используйте положительный tabindex (> 0); для редких случаев используйте tabindex="0" (включить в порядок) или -1 (программный фокус).
  • Кастомные интерактивы реагируют на Enter/Space и имеют корректную роль (лучше - нативная кнопка/ссылка).

Практическое ARIA: корректное использование ролей и распространённые анти-паттерны

HTML5 семантика и доступность (a11y): чек-лист для верстальщика - иллюстрация
  • Дублирование семантики: не ставьте role="button" на <button> и role="link" на <a> - это мешает, а не помогает.
  • ARIA вместо HTML: не пытайтесь "починить" отсутствие одним aria-label, если видимый текст уже есть - лучше связать корректно.
  • Неполные состояния: если используете aria-expanded, обновляйте его при каждом раскрытии/схлопывании, иначе скринридер будет сообщать неверное состояние.
  • Лишние landmark-роли: не размечайте всё как role="region"; регионы должны быть редкими и именованными (aria-label/aria-labelledby).
  • Скрытие контента: не скрывайте фокусируемые элементы через CSS так, что они остаются в таб-цепочке; при скрытии убирайте доступность корректно.
  • role="presentation"/role="none" без понимания: можно сломать списки/таблицы и чтение; применяйте только к строго декоративным оберткам.
  • Живые регионы где попало: aria-live используйте дозировано, иначе получатся "болтливые" интерфейсы и шум.

Быстрое тестирование и приоритеты правок: инструменты, чек-лист и сценарии

Если вы делаете чек лист доступности сайта для рабочей команды, разбивайте правки по приоритету: блокирующие (невозможно пользоваться), значимые (сильно мешает), косметические (улучшение). Для аудита доступности сайта сочетайте авто-проверку и ручные сценарии: автоинструменты находят типовые ошибки, а ручной проход выявляет проблемы фокуса, смысла и текстов.

Компактная таблица: что проверить в первую очередь

Элемент Проверка Приоритет Заметки (fast-track / deep-audit)
Landmarks Есть main, навигация в nav, уникальные области Высокий Fast: расставить семантические контейнеры. Deep: именовать регионы, убрать лишние.
Заголовки Иерархия без пропусков, смысловые названия Высокий Fast: исправить уровни. Deep: проверить логическую структуру разделов/section.
Формы label, fieldset/legend, ошибки связаны Критичный Fast: label + required + aria-describedby. Deep: фокус на ошибке, сводка ошибок.
Клавиатура Всё доступно Tab/Enter/Space, фокус виден Критичный Fast: вернуть outline/стили фокуса. Deep: фокус-менеджмент модалок/меню.
Изображения Корректный alt (смысл/декор) Средний Fast: заполнить alt у ключевых. Deep: проверить ссылки/кнопки-иконки на доступное имя.
ARIA Нет анти-паттернов, состояния обновляются Средний Fast: убрать лишние role. Deep: валидировать состояния (expanded, selected, live).

Сценарии проверки (2-4 подхода)

  1. Fast-track: 15-30 минут перед релизом. Пройдите страницу только клавиатурой, проверьте видимость фокуса, заголовки и формы; затем прогоните Lighthouse/axe и исправьте критичные ошибки.
  2. Deep-audit: перед редизайном/большим рефакторингом. Проверьте дерево доступности (Accessibility Tree), роли/имена/состояния, сценарии модальных окон и динамики; дополните ручной проверкой скринридером.
  3. Регрессия в CI. Подключите автоматические проверки (axe-core в e2e/юнит-тестах) и минимальные ручные сценарии на компоненты с кастомным взаимодействием.
  4. Компонентный подход для дизайн-системы. Фиксируйте требования a11y на уровне компонентов (кнопки, поля, модалки) и реиспользуйте их - так семантическая верстка HTML5 будет стабильнее между страницами.

Практические ответы на частые сложности верстки для a11y

Можно ли делать всё на div и "починить" ARIA-атрибутами?

Технически можно, но это почти всегда дороже и ломается чаще. Нативные HTML5 семантические теги и элементы управления дают правильные роли, имена и клавиатурное поведение без ручной поддержки.

Сколько section допустимо на странице и нужен ли заголовок внутри?

Сколько нужно по смыслу, но каждый <section> должен представлять отдельный раздел и обычно иметь заголовок. Если заголовка нет и раздел не смысловой - используйте <div>.

Что важнее для доступность сайта a11y: alt у картинок или правильные заголовки?

Оба пункта важны, но заголовки и структура чаще влияют на навигацию по странице целиком. Alt критичен там, где изображение передает смысл или является единственным текстом кнопки/ссылки.

Когда использовать aria-label, а когда aria-labelledby?

aria-labelledby предпочтительнее, когда на странице уже есть видимый текст, который должен стать именем элемента. aria-label используйте, если видимого текста нет и его нельзя добавить.

Почему не стоит ставить tabindex="1"..."9" для "красивого" порядка?

HTML5 семантика и доступность (a11y): чек-лист для верстальщика - иллюстрация

Положительный tabindex создает отдельный, хрупкий порядок фокуса и часто ломается при новых элементах. Держите порядок фокуса естественным через DOM и используйте tabindex="0"/-1 точечно.

Как быстро понять, что чек лист доступности сайта закрыт на минимальном уровне?

Страница полностью проходится клавиатурой, фокус не теряется, формы подписаны и дают понятные ошибки, а авто-проверка не показывает критичных нарушений. Если есть кастомные компоненты - обязателен ручной сценарий на них.

Что включать в аудит доступности сайта, кроме автоматических отчетов?

Ручные сценарии: клавиатура, проверка заголовков, проверка доступных имен/состояний, модальные окна и динамические уведомления. Автоотчеты находят не всё, поэтому используйте их как фильтр, а не как финальный вердикт.

Прокрутить вверх