Семантический HTML и альтернативный текст: фундамент доступного сайта
Почему кнопка должна быть button, как размечать ориентиры и заголовки и как писать alt для фото, иконок и графиков — с примерами кода

Часть 2 из 8 серии «Доступный веб на практике». Предыдущая часть: Доступность сайта: для кого она на самом деле и с чего начать.
Большая часть доступности достаётся бесплатно — если использовать правильные HTML-элементы. В этой части: кнопки и ссылки, ориентиры и заголовки, а также альтернативный текст для изображений, SVG-иконок и видео.
Семантический HTML — фундамент всего
Правильный HTML-элемент бесплатно даёт роль, имя, состояние, клавиатурную поддержку и поведение, которое пользователи вспомогательных технологий ожидают. Самая частая ошибка — пытаться воссоздать это вручную.
Кнопка — это <button>
<!-- ❌ Плохо: div притворяется кнопкой -->
<div class="btn" onclick="save()">Сохранить</div>
<!-- ✅ Хорошо -->
<button type="button" class="btn" onclick="save()">Сохранить</button>
У <div> из первого примера нет роли (скринридер прочитает просто текст), он не попадает в порядок табуляции и не реагирует на Enter и Space. Чтобы «починить» его, понадобится вот это:
<!-- Так тоже можно, но зачем? -->
<div role="button" tabindex="0" class="btn"
onclick="save()"
onkeydown="if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); save(); }">
Сохранить
</div>
И это всё ещё хуже настоящей кнопки: нет поддержки disabled, отправки формы, правильного поведения Space (настоящая кнопка срабатывает на отпускание). Вывод простой: используйте <button>. Стили сбрасываются одной строкой all: unset или парой свойств.
Ссылка или кнопка?
Правило: ссылка ведёт куда-то, кнопка что-то делает.
- Переход на другую страницу или к якорю —
<a href="...">. - Открыть меню, отправить форму, переключить тему, удалить запись —
<button>.
<!-- ❌ Ссылка, которая ничего не открывает -->
<a href="#" onclick="openMenu()">Меню</a>
<!-- ✅ -->
<button type="button" aria-expanded="false" aria-controls="main-menu">Меню</button>
Пользователи скринридеров ожидают от ссылок и кнопок разного поведения, а у ссылки без href вообще нет роли и фокуса.
Структура страницы: ориентиры
HTML5-элементы секционирования автоматически становятся ориентирами (landmarks), по которым пользователь скринридера прыгает одной клавишей:
<body>
<a class="skip-link" href="#main">Перейти к содержимому</a>
<header> <!-- banner -->
<a href="/"><img src="logo.svg" alt="Agama Labs — на главную"></a>
<nav aria-label="Основная"> <!-- navigation -->
<ul>
<li><a href="/services" aria-current="page">Услуги</a></li>
<li><a href="/portfolio">Портфолио</a></li>
<li><a href="/contact">Контакты</a></li>
</ul>
</nav>
</header>
<main id="main"> <!-- main -->
<h1>Услуги</h1>
...
</main>
<aside aria-labelledby="related-title"> <!-- complementary -->
<h2 id="related-title">Похожие статьи</h2>
...
</aside>
<footer> <!-- contentinfo -->
...
</footer>
</body>
Несколько деталей:
<main>— один на страницу.- Если на странице несколько
<nav>, подпишите их (aria-label="Основная",aria-label="Хлебные крошки"), иначе пользователь услышит «навигация, навигация». aria-current="page"сообщает, на какой странице пользователь находится. Стилизовать текущий пункт удобно по этому же атрибуту:nav a[aria-current="page"] { ... }.
Заголовки
Заголовки — главный способ навигации. По опросу WebAIM среди пользователей скринридеров, большинство ищет информацию на странице именно по заголовкам (WebAIM Screen Reader Survey).
- Уровни отражают структуру, а не размер шрифта. Нужен мелкий заголовок — делайте
<h2>и уменьшайте его в CSS. - Не пропускайте уровни: после
<h2>идёт<h3>, а не<h4>. - Обычно один
<h1>на страницу — название страницы. - Не делайте заголовком текст, который просто должен быть жирным.
Проверить структуру можно расширением вроде HeadingsMap или в панели скринридера.
Списки, таблицы и прочее
- Набор однородных элементов (пункты меню, карточки, шаги) —
<ul>/<ol>. Скринридер скажет «список, 5 элементов», и человек сразу поймёт объём. - Табличные данные —
<table>с<th scope="col">/<th scope="row">и<caption>. Таблицы для вёрстки не используйте. - Язык документа —
<html lang="ru">. Без него скринридер прочитает русский текст английским синтезатором. Фрагменты на другом языке размечайте:<span lang="en">accessibility</span>. - Заголовок вкладки
<title>уникален для каждой страницы: «Услуги — Agama Labs», а не одинаковое «Agama Labs» везде.
Изображения, иконки и альтернативный текст
Отсутствие alt — вторая по частоте ошибка в интернете. Но и «добавить хоть какой-то alt» — не решение.
Как выбрать alt
Задайте себе вопрос: что потеряет человек, если не увидит это изображение?
| Тип изображения | Что писать в alt |
|---|---|
| Информативное (фото товара, схема) | Суть того, что изображено, в контексте страницы |
| Функциональное (картинка внутри ссылки или кнопки) | Куда ведёт или что делает, а не что нарисовано |
| Декоративное (фоновый узор, «настроенческое» фото) | Пустой alt="" |
| Сложное (график, инфографика) | Краткий alt + подробное описание рядом в тексте |
| Изображение текста | Тот же текст |
<!-- Информативное -->
<img src="dashboard.png"
alt="Панель заказов: таблица с номером, статусом и суммой каждого заказа">
<!-- Функциональное: логотип-ссылка -->
<a href="/"><img src="logo.svg" alt="Agama Labs — на главную"></a>
<!-- Декоративное: пустой alt, а не отсутствующий -->
<img src="wave.svg" alt="">
<!-- Сложное: краткий alt + описание -->
<figure>
<img src="sales-2026.png" alt="График продаж за 2026 год, подробности ниже">
<figcaption>
Продажи росли с января по июнь с 120 до 340 заказов в месяц,
летом снизились до 260, в сентябре вернулись к 330.
</figcaption>
</figure>
Важная разница: пустой alt="" и отсутствующий alt — не одно и то же. Пустой говорит «это декорация, пропусти». Отсутствующий заставляет скринридер прочитать имя файла: «IMG underscore 4021 точка jpg».
Не начинайте alt со слов «изображение…» или «картинка…» — скринридер и так сообщит роль.
SVG-иконки
<!-- Декоративная иконка рядом с текстом: скрываем -->
<button type="button">
<svg aria-hidden="true" focusable="false" width="16" height="16">
<use href="#icon-trash"></use>
</svg>
Удалить
</button>
<!-- Кнопка только с иконкой: имя обязательно -->
<button type="button" aria-label="Удалить заказ №1042">
<svg aria-hidden="true" focusable="false" width="16" height="16">
<use href="#icon-trash"></use>
</svg>
</button>
<!-- Самостоятельная информативная SVG -->
<svg role="img" aria-labelledby="chart-title" viewBox="0 0 200 100">
<title id="chart-title">Конверсия выросла с 2% до 5%</title>
...
</svg>
Кнопка с одной иконкой без имени — это та самая «пустая кнопка» из статистики WebAIM (30,6% страниц). Скринридер скажет просто «кнопка».
Альтернатива aria-label — визуально скрытый текст. Он лучше переводится автоматическими переводчиками и надёжнее для голосового управления:
/* Скрыть визуально, но оставить для скринридеров */
.visually-hidden {
clip-path: inset(50%);
height: 1px;
width: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
}
<button type="button">
<svg aria-hidden="true" focusable="false">...</svg>
<span class="visually-hidden">Удалить заказ №1042</span>
</button>
Не используйте display: none или visibility: hidden для такого текста — они скрывают его и от скринридеров.
Видео и аудио
- У видео с речью — субтитры (
<track kind="captions">). Автоматические субтитры проверяйте вручную. - У аудио (подкаст) — текстовая расшифровка.
- Если важная информация передаётся только картинкой в видео (например, на экране показывают телефон, но не произносят его), нужна аудиодескрипция или текстовое описание.
- Никакого автовоспроизведения со звуком.
<video controls>
<source src="demo.mp4" type="video/mp4">
<track kind="captions" src="demo.ru.vtt" srclang="ru" label="Русский" default>
</video>
Серия «Доступный веб на практике»
- Доступность сайта: для кого она на самом деле и с чего начать
- Семантический HTML и альтернативный текст: фундамент доступного сайта — вы здесь
- Доступные формы: подписи, подсказки, ошибки и автозаполнение
- Клавиатура и фокус: как сделать сайт, которым можно пользоваться без мыши
- Контраст, анимация и размер кнопок: визуальная доступность сайта
- ARIA и динамический контент: когда атрибуты помогают, а когда вредят
- Доступность в React: id, фокус при смене маршрута и объявления
- Как тестировать доступность: автоматика, ручная проверка и чеклист
Следующая часть: Доступные формы: подписи, подсказки, ошибки и автозаполнение
Agama Labs — разработка сайтов и веб-приложений. Если хотите проверить доступность своего сайта, напишите нам: hello@agamalabs.com


