Доступность
Веб-доступность (сокращённо на английском — a11y) — это практика создания сайтов, которые могут быть использованы каждым человеком независимо от его инвалидности, скорости интернета, использовании старого или повреждённого оборудования, или просто нахождении в некомфортных местах. К примеру, добавление субтитров к видеороликам может помочь как глухим, слабослышащим людям, так и тем, кто в данный момент находится в шумной обстановке и не могут услышать звук со своего телефона. Аналогично, улучшив контрастность текста можно облегчить чтение людям с ослабленным зрением, а также тем, кто использует телефон при ярком солнечном свете.
Хотите сделать свои сайты доступными, но не знаете с чего начать?
Ознакомьтесь с руководством по планированию и управлению веб-доступностью от консорциума Всемирной паутины (World Wide Web Consortium, W3C)
Ссылка для перехода к основному контенту
Хорошая практика — добавить ссылку в начале каждой страницы, которая позволит пользователям быстро переходить к области основного содержимого на ней, что позволит пропустить повторяющееся элементы на веб-страницах.
Как правило, такая ссылка размещается в самом верху разметки главного компонента App.vue
, поскольку она должна стать первым фокусируемым элементом для всех страниц:
template
<ul class="skip-links">
<li>
<a href="#main" ref="skipLink" class="skip-link">Перейти к основному содержанию</a>
</li>
</ul>
Чтобы скрыть ссылку до тех пор, пока она не получит фокус, можно добавить следующие стили:
css
.skip-link {
white-space: nowrap;
margin: 1em auto;
top: 0;
position: fixed;
left: 50%;
margin-left: -72px;
opacity: 0;
}
.skip-link:focus {
opacity: 1;
background-color: white;
padding: 0.5em;
border: 1px solid black;
}
При переходе на новую страницу возвращаем фокус обратно на ссылку. Для этого вызовем соответствующий метод на элементе через ref (при условии использования vue-router
):
vue
<script setup>
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const skipLink = ref()
watch(
() => route.path,
() => {
skipLink.value.focus()
}
)
</script>
Документация о реализации ссылок для перехода к основному содержимому
Структурирование содержимого
Одна из важнейших частей доступности — разработка дизайна с прицелом на доступность. Дизайн должен рассматривать не только цветовой контраст, шрифт, размер текста и язык, но и то, как структурировать содержимое в приложении.
Заголовки
Пользователи могут осуществлять навигацию по заголовкам в приложении. Наличие заголовков для каждого раздела даст общее представление об содержащейся в них информации. Несколько полезных рекомендаций для улучшения доступности заголовков:
- Используйте вложенные заголовки в порядке очерёдности:
<h1>
-<h6>
- Не пропускайте заголовки внутри раздела
- Следует использовать именно теги заголовков вместо стилизации текста
Узнать подробнее про заголовки
template
<main role="main" aria-labelledby="main-title">
<h1 id="main-title">Основной заголовок</h1>
<section aria-labelledby="section-title-1">
<h2 id="section-title-1"> Заголовок раздела </h2>
<h3>Вложенный заголовок раздела</h3>
<!-- Содержимое -->
</section>
<section aria-labelledby="section-title-2">
<h2 id="section-title-2"> Заголовок раздела </h2>
<h3>Вложенный заголовок раздела</h3>
<!-- Содержимое -->
<h3>Вложенный заголовок раздела</h3>
<!-- Содержимое -->
</section>
</main>
Ориентиры
Ориентиры (landmarks) предоставляют программный доступ к разделам приложения. Пользователи, использующие вспомогательные технологии, могут перейти непосредственно к каждому разделу приложения минуя остальное содержимое. Для этого следует использовать ARIA roles.
HTML | ARIA Role | Назначение ориентира |
---|---|---|
header | role="banner" | Основной заголовок: заголовок страницы |
nav | role="navigation" | Коллекция ссылок для перемещения по странице или другим страницам |
main | role="main" | Основное или самое важное содержимое на странице |
footer | role="contentinfo" | Информация о странице: сноски, авторские права, ссылки на политику конфиденциальности |
aside | role="complementary" | Дополнение к основному содержимому |
search | role="search" | Раздел, содержащий функциональность поиска по приложению |
form | role="form" | Коллекция элементов формы |
section | role="region" | Сопутствующее содержимое, которое пользователь возможно захочет изучить. Для такого элемента нужно указать метку |
Семантические формы
При создании формы можно использовать следующие элементы: <form>
, <label>
, <input>
, <textarea>
, и <button>
Как правило, метки размещаются сверху или слева от полей формы:
template
<form action="/dataCollectionLocation" method="post" autocomplete="on">
<div v-for="item in formItems" :key="item.id" class="form-item">
<label :for="item.id">{{ item.label }}: </label>
<input
:type="item.type"
:id="item.id"
:name="item.id"
v-model="item.value"
/>
</div>
<button type="submit">Отправить</button>
</form>
Обратите внимание, можно добавить autocomplete='on'
к самому элементу формы, и этот атрибут применится ко всем полям формы. Каждому полю можно задать свои значения атрибута autocomplete.
Метки
Добавляйте метки для описания полей формы, а также создания связи между элементами с атрибутами for
и id
:
template
<label for="name">Название:</label>
<input type="text" name="name" id="name" v-model="name" />
Если посмотреть элемент через инструменты разработки (например, DevTools в браузере Chrome) и перейти на вкладку Accessibility внутри раздела Elements, то можно увидеть, что имя поля извлекается из связанной с ним метки:
Предупреждение
Часто можно встретить случаи, когда поле ввода находится внутри элемента с меткой:
template
<label>
Название:
<input type="text" name="name" id="name" v-model="name" />
</label>
Однако явное указание меткам соответствующего идентификатора лучше поддерживается вспомогательными технологиями.
aria-label
Указать имя поля для использования вспомогательными технологиями можно с помощью атрибута aria-label
.
template
<label for="name">Название:</label>
<input
type="text"
name="name"
id="name"
v-model="name"
:aria-label="nameLabel"
/>
Можно убедиться самостоятельно что имя элемента изменилось с помощью инструментов разработки Chrome DevTools:
aria-labelledby
Использование атрибута aria-labelledby
похоже на aria-label
, за исключением того, что текст метки показывается на экране. Он создаёт связь между элементами с атрибутом id
, причём допускается указывать несколько id
:
template
<form
class="demo"
action="/dataCollectionLocation"
method="post"
autocomplete="on"
>
<h1 id="billing">Выставление счетов</h1>
<div class="form-item">
<label for="name">Название:</label>
<input
type="text"
name="name"
id="name"
v-model="name"
aria-labelledby="billing name"
/>
</div>
<button type="submit">Отправить</button>
</form>
aria-describedby
Атрибут aria-describedby используется аналогично aria-labelledby
, но предоставляет дополнительную информацию, которая может потребоваться пользователю. Его можно использовать для описания критериев любых полей:
template
<form
class="demo"
action="/dataCollectionLocation"
method="post"
autocomplete="on"
>
<h1 id="billing">Выставление счетов</h1>
<div class="form-item">
<label for="name">Полное название:</label>
<input
type="text"
name="name"
id="name"
v-model="name"
aria-labelledby="billing name"
aria-describedby="nameDescription"
/>
<p id="nameDescription">Пожалуйста, укажите имя и фамилию.</p>
</div>
<button type="submit">Отправить</button>
</form>
Вы можете просмотреть описание, заглянув в Chrome DevTools:
Подсказка внутри поля (Placeholder)
Старайтесь ограничить использование подсказок внутри полей, так как они могут запутать пользователя.
Одна из проблем заключается в том, что по умолчанию подсказки внутри полей не соответствуют критериям цветового контраста. Попытка исправить цветовой контраст может сделать подсказку похожей на уже заполненное поле. Посмотрите на следующий пример: подсказка поля Last Name соответствует критериям цветового контраста, но не отличается от введённого значения:
template
<form
class="demo"
action="/dataCollectionLocation"
method="post"
autocomplete="on"
>
<div v-for="item in formItems" :key="item.id" class="form-item">
<label :for="item.id">{{ item.label }}: </label>
<input
type="text"
:id="item.id"
:name="item.id"
v-model="item.value"
:placeholder="item.placeholder"
/>
</div>
<button type="submit">Отправить</button>
</form>
css
/* https://www.w3schools.com/howto/howto_css_placeholder.asp */
#lastName::placeholder {
/* Chrome, Firefox, Opera, Safari 10.1+ */
color: black;
opacity: 1; /* Firefox */
}
#lastName:-ms-input-placeholder {
/* Internet Explorer 10-11 */
color: black;
}
#lastName::-ms-input-placeholder {
/* Microsoft Edge */
color: black;
}
Поэтому будет лучше всего перенести всю необходимую информацию для заполнения за пределы полей формы.
Инструкции
При добавлении инструкций для заполнения убедитесь, что они связаны с нужным полем. Можно указать дополнительные инструкции и привязать несколько идентификаторов в атрибуте aria-labelledby
. Это делает дизайн более гибким.
template
<fieldset>
<legend>Использование aria-labelledby</legend>
<label id="date-label" for="date">Текущая дата:</label>
<input
type="date"
name="date"
id="date"
aria-labelledby="date-label date-instructions"
/>
<p id="date-instructions">MM/DD/YYYY</p>
</fieldset>
В качестве альтернативы, можно привязать инструкции к полю с помощью атрибута aria-describedby
:
template
<fieldset>
<legend>Использование aria-describedby</legend>
<label id="dob" for="dob">Дата рождения:</label>
<input type="date" name="dob" id="dob" aria-describedby="dob-instructions" />
<p id="dob-instructions">MM/DD/YYYY</p>
</fieldset>
Скрытие содержимого
Обычно не рекомендуется визуально скрывать лейблы, даже если для поля ввода задано вспомогательное имя. Тем не менее, если смысл поля понятен из контекста, то лейбл можно скрыть.
Рассмотрим следующее поле поиска:
template
<form role="search">
<label for="search" class="hidden-visually">Поиск: </label>
<input type="text" name="search" id="search" v-model="search" />
<button type="submit">Поиск</button>
</form>
В данном случае можно скрыть лейбл, поскольку кнопка поиска поможет зрячим пользователям определить назначение поля.
С помощью CSS-класса визуально скрываем элемент, но оставляем их доступными для вспомогательных технологий:
css
.hidden-visually {
position: absolute;
overflow: hidden;
white-space: nowrap;
margin: 0;
padding: 0;
height: 1px;
width: 1px;
clip: rect(0 0 0 0);
clip-path: inset(100%);
}
aria-hidden="true"
Добавление aria-hidden="true"
скроет элемент от обнаружения вспомогательными технологиями, но оставит его визуально доступным для остальных пользователей. Не используйте его на фокусируемых элементах, только для декоративных, дублирующихся или не отображаемых на экране элементов.
template
<p>Это не скрыто от устройств чтения с экрана.</p>
<p aria-hidden="true">Это скрыто от устройств чтения с экрана.</p>
Кнопки
При использовании кнопок внутри формы, следует указывать их тип, чтобы избежать отправки формы. Для создания кнопок также можно использовать обычное поле ввода:
template
<form Кнопки="/dataCollectionLocation" method="post" autocomplete="on">
<!-- Кнопки -->
<button type="button">Отменить</button>
<button type="submit">Отправить</button>
<!-- Кнопки ввода -->
<input type="button" value="Отменить" />
<input type="submit" value="Отправить" />
</form>
Функциональные изображения
Для создания функциональных изображений можно использовать приведенную ниже технику.
Поля ввода
- Изображение будет работать как кнопка отправки формы
template<form role="search"> <label for="search" class="hidden-visually">Поиск: </label> <input type="text" name="search" id="search" v-model="search" /> <input type="image" class="btnImg" src="https://img.icons8.com/search" alt="Поиск" /> </form>
Иконки
template
<form role="search">
<label for="searchIcon" class="hidden-visually">Поиск: </label>
<input type="text" name="searchIcon" id="searchIcon" v-model="searchIcon" />
<button type="submit">
<i class="fas fa-search" aria-hidden="true"></i>
<span class="hidden-visually">Поиск</span>
</button>
</form>
Стандарты
Инициатива веб-доступности (Web Accessibility Initiative, WAI) консорциума Всемирной паутины (World Wide Web Consortium, W3C) разработала стандарты для обеспечения доступности:
- Руководства по доступности пользовательских программ (User Agent Accessibility Guidelines, UAAG)
- касается браузеров и медиа-плееров, включая вспомогательные технологии
- Руководства по доступности средств разработки авторского контента (Authoring Tool Accessibility Guidelines, ATAG)
- распространяется на приложения для создания веб-страниц
- Руководства по доступности веб-содержимого (Web Content Accessibility Guidelines, WCAG)
- относится к содержимому в вебе, используемому разработчиками, программами для создания веб-страниц и инструментами для оценки доступности
Руководства по доступности веб-содержимого (WCAG)
WCAG 2.1 продолжение WCAG 2.0, в котором были учтены новые веб-технологии. При разработке новых или обновлении существующих политик по обеспечению веб-доступности консорциум W3C настоятельно рекомендует использовать последнюю версию стандарта WCAG.
Четыре базовых принципа WCAG 2.1 (сокращённо POUR):
- Perceivable (Воспринимаемость)
- Представленная информация должна быть доступной для всех пользователей
- Operable (Управляемость)
- Компоненты интерфейса, элементы управления и навигации поддерживают управление с клавиатуры
- Understandable (Понятность)
- Информация и функционирование интерфейса должны быть понятны всем пользователям
- Robust (Надёжность)
- Рабочий доступ к информации вне зависимости от технологии, используемой пользователями
Инициатива веб-доступности – Доступные полнофункциональные интернет-приложения (Accessible Rich Internet Applications, WAI-ARIA)
Стандарт WAI-ARIA компании от W3C служит руководством по созданию динамического содержимого и расширенных средств для управления интерфейсом.
Ресурсы
Документация
- WCAG 2.0
- WCAG 2.1
- Accessible Rich Internet Applications (WAI-ARIA) 1.2
- WAI-ARIA Authoring Practices 1.2
Вспомогательные технологии
- Программы для чтения экрана
- Программы для увеличения/уменьшения области просмотра
Тестирование
- Автоматизированные инструменты
- Инструменты для работы с цветом
- Другие полезные инструменты
Пользователи
Согласно Всемирной организации здравоохранения, 15% населения мира имеет какую-либо форму инвалидности, 2-4% из них — тяжёлую форму. По оценкам ВОЗ, в мире насчитывается примерно 1 миллиард инвалидов, что делает их самой крупной группой меньшинств в мире.
Существует очень много инвалидностей, которые примерно можно разделить на четыре категории:
- Визуальные - Таким пользователям могут помочь программы для чтения с экрана, увеличения экрана, управления контрастностью экрана, либо брайлевский дисплей.
- Слуховые - Таким пользователям могут помочь субтитры, расшифровки или видео с языком жестов.
- Двигательные - Таким пользователям могут помочь разные вспомогательные технологии при двигательных нарушений: программы для распознавания голоса, отслеживания глаза, устройства для простого управления, головные щуп-указки, устройства для управления указателем мыши без рук, безразмерные трекбол-мыши, сенсорные клавиатуры или другие вспомогательные технологии.
- Когнитивные - Таким пользователям могут помочь дополнительные медиа, структурированная организация содержимого, понятный и простой стиль написания. Ознакомьтесь со следующими ссылками WebAim, чтобы понять их у пользователей.
Посмотрите следующие ссылки из WebAim для понимания проблемы со стороны пользователей: