TGViewer
<divelopers> <divelopers> @alexnozer_dev · 1.18K subscribers
Post #380 750
Пустые кнопки и ссылки

По данным отчёта WebAIM Million 2026 на 46.3% сайтов встречаются пустые ссылки и на 30.6% сайтов — пустые кнопки. Обе эти проблемы входят в топ 6 самых частых нарушений доступности, обнаруживаемых с помощью WAVE.

Пустые кнопки и ссылки — это те, у которых имя не задано ни одним из способов и браузер вычисляет его как пустую строку. Вспомогательные технологии используют имя для идентификации элементов, а люди полагаются на это при взаимодействии.

- Программы чтения с экрана озвучивают тип элемента и его имя: «Каталог, ссылка» или «Добавить в корзину, кнопка». Пользователь слышит и понимает, что за элемент и что он делает;
- Программы голосового управления ищут элементы по имени: «Нажми Каталог» или «Нажми Добавить в корзину» программа найдёт элемент на экране и нажмёт на него;
- Программы чтения с экрана и специальные браузерные расширения выводят все ссылки или кнопки со страницы в виде списка, имя используется при формировании этого списка.

При отсутствии имени элементы будут анонимными. Просто какая-то «Ссылка» или «Кнопка». Не понятно назначение, сложно идентифицировать, не удобно взаимодействовать. Всё это создаёт препятствия для пользователей.

Чаще всего пустые ссылки и кнопки получаются, когда они отображаются в виде иконок: три горизонтальные линии, тележка, крестик, урна, стрелка, плюс и так далее. Визуально может быть понятно, но программно — нет.

<button type="button">
<svg>
<!-- иконка с тремя линиями -->
</svg>
</button>

<a
href="/cart"
class="icon icon--cart"
>
<!-- иконка тележки в CSS -->
</a>

<button type="button">
<i class="fa-solid fa-trash">
<!-- иконка мусорки из шрифта -->
</i>
</button>

<a href="/catalog?page=3">
<!-- внешняя иконка стрелки -->
<img
src="/assets/arrow-left.svg"
alt=""
>
</a>


Это примеры «пустых» кнопок и ссылок без имени. Базовое правило таково: у кнопок и ссылок должно быть короткое, лаконичное и понятное имя, заданное одним из способов:

- атрибут aria-labelledby;
- атрибут aria-label;
- элемент <label> (только для <button>);
- текстовый контент;
- атрибут title.

Порядок указывает приоритет применения. aria-label переопределяет имя, заданное через <label>, а aria-labelledby, в свою очередь, переопределяет имя, заданное в aria-label. Стоит выбрать какой-то один способ и не смешивать во избежание неожиданностей.

Наилучшим из способов будет видимый текстовый контент. Он соответствует первому правилу ARIA: не полагаться на атрибуты ARIA и использовать встроенные способы. Также видимый текст можно прочесть в отличие от скрытого.

То есть кнопка или ссылка с иконкой и текстом — лучшее из возможных решений. Глядя на текст становится понятно, что нужно сказать для активации элемента голосом. Также люди с когнитивными нарушениями могут не понимать метафору иконки.

<button type="button"> 
<svg aria-hidden="true">
<!-- иконка с тремя линиями -->
</svg>
Меню
</button>

<a
href="/cart"
class="icon icon--cart"
>
<!-- иконка тележки в CSS -->
Корзина
</a>

<label for="delete">
Удалить
</label>
<button type="button" id="delete">
<i
class="fa-solid fa-trash"
aria-hidden="true"
>
<!-- иконка мусорки из шрифта -->
</i>
</button>

<a href="/catalog?page=3">
<!-- внешняя иконка стрелки -->
<img
src="/assets/arrow-left.svg"
alt=""
>
Предыдущая страница
</a>


При наличии видимого текста стоит скрыть иконки, если они выполняют только функцию визуальной подсказки и текст уже описывает это. Подойдёт атрибут aria-hidden="true" или пустой alt="" у <img>, что скрывает элементы из дерева доступности.

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

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

- Элемент <title> внутри <svg> задаёт альтернативный текст для изображения-иконки (работает как alt у <img>) и используется как текстовый контент для вычисления имени;
- Специальный класс visually-hidden делает элемент визуально невидимым, но всё ещё доступным как текстовый контент, который задаёт имя;
- Атрибут title задаёт имя элементу при отсутствии контента, но текст в атрибуте отображается в виде системной всплывающей подсказки только при наведении (и при фокусе в Edge);
- Атрибут alt задаёт альтернативный текст для изображения и его значение также используется как текстовый контент и задаёт имя элементу.

Элемент <title> и атрибут title создают системные всплывающие подсказки. C ними много проблем: появляются только при наведении мыши, не реагируют на настройки размера текста и так далее. Не рекомендуется их использовать.

<button type="button">
<svg>
<title>
Меню
</title>
<!-- иконка с тремя линиями -->
</svg>
</button>

<a
href="/cart"
class="icon icon--cart"
>
<!-- иконка тележки в CSS -->
<span class="visually-hidden">
Корзина
</span>
</a>

<button
type="button"
title="Удалить"
>
<i class="fa-solid fa-trash">
<!-- иконка мусорки из шрифта -->
</i>
</button>

<a href="/catalog?page=3">
<!-- внешняя иконка стрелки -->
<img
src="/assets/arrow-left.svg"
alt="Предыдущая страница"
>
</a>


Если прибегнуть к ARIA, то имя кнопок и ссылок можно задать с помощью атрибутов aria-label или aria-labelledby. Можно указать как на самих элементах, так и на иконках в виде альтернативного текста, который будет использован как текстовый контент кнопки.

<button type="button">
<svg
role="img"
aria-label="Меню"
>
<!-- иконка с тремя линиями -->
</svg>
</button>

<a
href="/cart"
class="icon icon--cart"
aria-labelledby="cart-label"
>
<!-- иконка тележки в CSS -->
<span id="cart-label" hidden>
Корзина
</span>
</a>

<span id="del-icon" hidden>
Удалить
</span>
<button type="button">
<i
class="fa-solid fa-trash"
role="img"
aria-labelledby="del-icon"
>
<!-- иконка мусорки из шрифта -->
</i>
</button>

<a
href="/catalog?page=3"
aria-label="Предыдущая страница"
>
<!-- внешняя иконка стрелки -->
<img
src="/assets/arrow-left.svg"
alt=""
>
</a>


- role="img" превращает <svg> в <img>, а aria-label в таком случае работает как alt. Альтернативный текст используется как имя элемента;
- aria-labelledby ссылается на элемент по указанному id и текст этого элемента используется как имя, при этом сам элемент может быть скрыт;
- aria-labelledby также работает как alt для элементов с role="img" и берёт альтернативный текст из указанного элемента;
- самый простой и короткий способ — просто указать ссылке или кнопке атрибут aria-label, который задаёт имя элементу.

Какой бы способ вы ни выбрали, всегда проверяйте значение Name у элемента на панели Accessibility в DevTools и проходитесь программой чтения с экрана. Не лишним будет прогнать страницу через Axe и подключить линтеры.

#html #a11y
  • 👍 8
  • ❤ 2
  • ⚡ 1
  • 🔥 1
More from @alexnozer_dev
  1. Sep 21, 2026Реализация пользовательских атрибутов Под конец прошлого года я рассказывал об API пользов…
  2. Sep 14, 2026Подклассы Event вместо CustomEvent Многие библиотеки предоставляют систему событий в качес…
  3. Sep 11, 2026Эволюция стилей в темах Shopify Адам Ватан на днях поделился новостью, что Shopify выкупил…
  4. Sep 9, 2026Persistent Widgets Многие сайты не должны быть SPA. Но иногда эта архитектура продиктована…
  5. Sep 7, 2026Processing Instructions и маркеры В DOM всё представлено в виде узлов (Node) разных типов.…
  6. Sep 1, 2026@scope и потоковая передача HTML Ноам Розенталь поделился интересной техникой, в которой с…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →