Перевод статьи Links vs. Buttons in Modern Web Applications с сайта marcysutton.com для CSS-live.ru, автор — Марси Саттон
Github: ссылки или кнопки?
Одна из вечных тем во фронтенд-доступности — неразбериха между ссылками и кнопками. Ну, HTML-элементы, которые открывают ссылки в новом окне или отправляют форму, знаете? В веб-приложениях на JavaScript мы по-прежнему путаемся, какой элемент выбрать для пользовательского действия. Чтобы развеять туман, я покажу примеры использования для ссылок и кнопок в приложениях с отрисовкой на клиенте и помогу вам принимать лучшие решения с точки зрения UI.
Кнопки
Почему-то люди становятся веб-разработчиками,так и не узнав про HTML-элемент <button>. (Мне и самой потребовалось несколько лет, пока я узнала, для чего нужны заголовки h1-h6, так что бывает). Могучая кнопка и правда крутая. Вот что она может делать:
- Получать фокус с клавиатуры по умолчанию
- Делать «клик» по нажатию на пробел
- Отправлять данные формы на сервер
- Очищать форму
- Блокироваться с помощью атрибута
disabled
- Давать подсказку скринридеру с помощью неявного атрибута
role="button"
- Показывать состояния
∶focus
,∶hover
,∶active
,∶disabled
Если добавить немного скрипта,кнопка идеальный элемент для:
- Открывания модального окна
- Вызова всплывающего меню
- Переключения интерфейса
- Проигрывания медиа-контента
- Вставки с помощью JS в случае, если они работают только с помощью JS
Ссылки
Вот несколько базовых возможностей ссылок, или якорей, или фундамента веба:
- Создавать гипертекст, сеть онлайн-ресурсов
- Перевести пользователя на новую страницу или окно
- Изменять URL
- Вызвать браузерные перерисовку/перезагрузку
- Переходить по якорям внутри страницы
- Связывать между собой разные части приложения с отрисовкой на клиенте
- Способны принимать фокус по умолчанию с помощью атрибута
href
- Регистрируют клик с помощью клавиши
Enter
- Имеют неявную роль link
- Не блокируются как кнопки, но их можно сделать неактивными с помощью
tabindex="-1"
иaria-hidden="true"
- Могут открываться в новых окнах (а раньше — и во фреймах)
- Показывать состояния
∶link
,∶visited
,∶focus
,∶hover
,∶active
Лично для меня самое главное различие между ссылкой и кнопкой — то, что ссылки перемещают пользователя на новый ресурс, унося его из текущего контекста (внутренние ссылки — единственная загвоздка здесь). Кнопка переключает что-то в интерфейсе, например, видео-плеер, или вызывает новый контент в том же самом контексте, например, всплывающее меню, использующее aria-haspopup
.
Что такое навигация? А что маршрутизация?
Изменение URL означает, что пользователь переходит на новую страницу. Это перезагружает браузер с новым ресурсом и перерисовывает пиксели. Навигация может вызываться с помощью действий формы, якорных ссылок и JavaScript-свойства location
.
Подобно сортировке писем на почте,маршрутизация — механизм для подключения сетевых запросов с соответствующим контентом в приложении. Маршрутизаторы — общая технология для множества разных веб-фреймворков (помню, как на заре своей карьеры я балдела от PHPшных), ставящая в соответствие представления и их части определенным фрагментам URL. Благодаря написанию динамических маршрутов, новый контент можно создавать динамически (без хардкода)
Откуда возникает путаница?
В мире клиентских веб-приложений построенных с помощью Angular, Ember или React, браузерная перерисовка может вызваться в любой момент. Немного неясно, какой элемент лучше подходит для дела, когда вы можете выполнять тот же код, что для маршрута, но с обработчиком клика кнопки и без изменения URL. К примеру, если я открываю панель над существующим контентом страницы, я перехожу сюда или переключаю интерфейс? Зависит ли это от того, есть ли у этой панели свой собственный URL? Вот код, который я видела недавно:
<a href="#" tabindex="0" ng-click="userPicker.userClicked(true)" aria-label="Some username"></a>
По первому впечатлению я посчитала, что это надо заменить на элемент button
, поскольку нет значения в href
, но есть tabindex="0"
и привязка обработчика ng-click
. Выглядит очевидно, да? Мне сказали, что он должен оставаться якорем, поскольку «он перенаправляет на внешние ссылки и страницу профиля». Это стало ясно только после изучения JavaScript-кода, который вызывается во многих подобных местах по привязке обработчика ng-click
на элементе button
. Неужели обязательно надо так глубоко копать, чтобы помочь выбрать правильный элемент?
Если в чисто клиентском приложении фокус обрабатывается правильно, это может не сказаться на пользователе — у ссылки ng-click
и tabindex
останется по-прежнему неявная роль ссылки. Однако,при декларативном подходе намного лучше было бы использовать заполненный href
и маршрутизацию, если якорь перенаправляет пользователя на новый ресурс. Tabindex и события click
, привязанные к тегу ссылки — антипатерн разметки, который еще аукнется тем, кто позднее будет писать код и проверять его.
Если делать маршрутизацию основной частью веб-приложения, то веб-разработчикам будет намного проще использовать ссылки и понять предназначение кнопок. А еще с ним проще создавать серверные JavaScript-приложения с прогрессивным улучшением, пользуясь шаблонами URL, а не полагаясь на события по клику.
Роль UX в разработке доступных приложений
Я скажу это вслух: эта путаница часто начинается с дизайна и UX. Компонент дизайна приходит к нам с прямоугольными кнопками интерфейса, и — потому что так надо — в коде они должны быть ссылками. Где это становится проблемой?
Если пользователь скринридера обратится в техподдержку и получит инструкцию «кликнуть на кнопку» в вашем UI, которая на самом деле написана в коде как ссылка, для него может оказаться проблемой найти ее. Не забывайте и о голосовых интерфейсах: если вы произнесёте команду кликнуть на кнопку, которая в коде похожа на ссылку, вы столкнетесь с проблемами, нет?
Фреймворки, по общему признанию, стирают эту грань и только способствуют выбору неправильного элемента, как в примере с ng-click
выше. Можно использовать JavaScript для запуска асинхронной отправки формы на нужном нам элементе (даже без тега <form>
, но это еще не повод от него отказываться). Аналогично, можно инициировать изменения представления без маршрутизации, даже если их лучше всего обрабатывать с помощью ссылки. Одни элементы подходят в одном случае, другие — в другом: всё дело в том, чтобы использовать нативные возможности этого элемента по максимуму.
Заметили разницу?
Что можно для этого сделать?
Вернитесь к дизайну и сделайте ссылки похожими на ссылки, а кнопки — на кнопки. Без двусмысленности разработчикам станет легче писать более доступный код, лучше отвечающий ожиданиям пользователей. (Можно ли кликнуть правой кнопкой мыши на эту квадратную кнопку, чтобы открыть в новом окне?)
В разработке:
- Если пользователь скринридера перейдет табом на интерактивный элемент, подскажет ли роль этого элемента, чего от него ждать? (Уводит ли он куда-то с текущей страницы? Об этом хорошо бы узнать заранее.)
- Отключаете ссылочные фичи типа смены URL или правого клика? Подумайте о кнопке.
- Поддерживайте маршрутизацию в вашем приложении с помощью
href
,ng-href
, и так далее. - Навигация по страницам заслуживает изменения заголовка и истории.
Это ещё не конец.
Уверена, что к этой теме придется вечно возвращаться снова и снова, как и все эти годы. Воплощая интерфейс в коде, вам каждый раз придется с трудом выбирать, какой элемент правильный в данном случае… и есть уйма способов сделать одно и то же. И если при этом вы принимаете компетентные решения, то это лучшее, что в ваших силах.
Разработчики, которым предстоит работать с кодом после вас, благодаря декларативности смогут легче освоить эту науку. И самое главное, подумайте об ожиданиях ваших пользователей от взаимодействия, а не бросайтесь с дизайном интерфейса в крайности. Когда интерфейс интуитивно понятен, он меньше напрягает, и пользователи остаются довольны.
P.S. Это тоже может быть интересно: