Accessibility в Go: делаем софт доступным для всех

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Когда код говорит: «Я тебя слышу»

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

Accessibility (или a11y — от «a» + 11 букв + «y») — это не про «сделать галочку для галочки». Это про то, чтобы ваш Go-сервис не выключал свет для 15% населения Земли. В этой статье мы разберем, как внедрить доступность в Go-проекты без фанатизма, но с реальной пользой. Поехали!

Почему accessibility в Go — это не опция, а стандарт

Go — язык для бэкенда, но это не значит, что он не участвует в создании доступного интерфейса. Если вы пишете API для фронтенда, генерируете HTML на сервере или создаете CLI-утилиты — вы уже влияете на доступность. Плохая новость: многие Go-разработчики думают, что «a11y — это забота фронтендеров». Хорошая новость: вы можете это исправить за вечер.

Что такое веб-доступность с точки зрения Go?

Веб-доступность (web accessibility) — это способность сайта или приложения быть использованным людьми с разными ограничениями: зрение, слух, моторика, когнитивные способности. В контексте Go это означает:

  • Корректную разметку HTML, сгенерированного сервером (например, через html/template);
  • Правильные ARIA-атрибуты для динамического контента;
  • Логичную навигацию с клавиатуры;
  • Понятные сообщения об ошибках (не «Error 500», а «Не удалось сохранить файл: недостаточно места»).

И да, Go — идеальный язык для этого. Его строгая типизация и встроенные инструменты позволяют проверять шаблоны на лету. Но обо всем по порядку.

Семантическая разметка: фундамент доступности в Go

Когда вы генерируете HTML через html/template, вы — архитектор интерфейса. Если ваш код плюет <div> на каждую кнопку, скринридеры (screen readers) не поймут, что это за элемент. А если использовать <button> — они скажут: «Кнопка. Нажмите, чтобы отправить форму».

Пример: доступная форма на Go

Допустим, вы пишете форму регистрации. Плохой вариант:

// Плохо: нет семантики
tmpl := `<div class="form">
    <div>Имя</div>
    <input type="text" id="name">
    <div class="error">{{.NameError}}</div>
</div>`

Хороший вариант — с <label> и aria-describedby:

// Хорошо: семантическая разметка + ARIA
tmpl := `<form>
    <label for="name">Имя</label>
    <input type="text" id="name" aria-describedby="name-error">
    <span id="name-error" role="alert">{{if .NameError}}{{.NameError}}{{end}}</span>
</form>`

Что изменилось? Скринридер теперь знает: это форма, поле ввода связано с меткой, а ошибка — это alert. Пользователь услышит: «Имя. Редактировать текст. Ошибка: поле обязательно».

ARIA-атрибуты: когда HTML не справляется

Иногда стандартных тегов недостаточно. Например, вы делаете табы (tabs) на Go + HTMX. Без ARIA они будут звучать как «ссылка, ссылка, ссылка...». А с ARIA — как «Вкладка 1, выбрана. Вкладка 2. Вкладка 3».

Как добавить ARIA в Go-шаблоны

ARIA-атрибуты передаются как обычные атрибуты в HTML. Вот пример для табов:

<div role="tablist" aria-label="Настройки профиля">
    <button role="tab" aria-selected="{{if eq .Tab "profile"}}true{{else}}false{{end}}" 
            aria-controls="panel-profile" id="tab-profile">Профиль</button>
    <button role="tab" aria-selected="{{if eq .Tab "security"}}true{{else}}false{{end}}" 
            aria-controls="panel-security" id="tab-security">Безопасность</button>
</div>
<div role="tabpanel" id="panel-profile" aria-labelledby="tab-profile">
    {{template "profile" .}}
</div>

Обратите внимание: aria-selected динамически меняется в зависимости от состояния. Это критически важно — скринридер должен знать, какая вкладка активна.

Клавиатурная навигация: без мыши тоже можно

Многие пользователи с моторными нарушениями не используют мышь. Они навигируют по Tab, Shift+Tab и Enter. Ваш Go-код должен это поддерживать.

Ловушка фокуса (focus trap) для модальных окон

Когда открывается модалка, фокус должен оставаться внутри нее. Пользователь не должен случайно уйти в фон. Вот как это сделать на Go с помощью JavaScript-хука:

// В Go-шаблоне
<div id="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title">
    <h2 id="modal-title">Подтверждение</h2>
    <p>Вы уверены, что хотите удалить аккаунт?</p>
    <button id="confirm-btn">Да</button>
    <button id="cancel-btn">Отмена</button>
</div>

// JavaScript (встроенный или из отдельного файла)
// При открытии: document.getElementById('confirm-btn').focus()
// При Tab: зацикливаем фокус между confirm-btn и cancel-btn

В Go вы можете передать начальное состояние фокуса через атрибут autofocus:

<button id="confirm-btn" autofocus>Да</button>

Тестирование доступности: как не пропустить баги

Accessibility — это не «написал и забыл». Нужно тестировать. И Go здесь — ваш друг.

Автоматическое тестирование с axe-core

Вы можете запускать axe-core (инструмент от Deque) прямо из Go-тестов. Например, через chromedp — драйвер Chrome для Go:

package main

import (
    "context"
    "log"
    "github.com/chromedp/chromedp"
    "github.com/chromedp/cdproto/cdp"
)

func TestAccessibility(t *testing.T                

Блоги

Рекомендаций по книгам