Принципы веб-доступности

Веб-доступность начинается с корректной HTML-семантики. Preact, как и React, работает поверх обычного HTML, поэтому именно теги определяют, как интерфейс воспринимается вспомогательными технологиями: скринридерами, голосовым управлением, клавиатурной навигацией.

Использование <div> и <span> вместо семантических элементов лишает интерфейс структуры. Корректные теги (<header>, <nav>, <main>, <section>, <article>, <button>, <label>, <form>) позволяют вспомогательным средствам интерпретировать назначение элементов без дополнительных ухищрений.

В Preact-компонентах это означает:

function Header() {
  return (
    <header>
      <nav>
        <ul>
          <li><a href="/">Главная</a></li>
        </ul>
      </nav>
    </header>
  );
}

Семантика должна закладываться на уровне JSX, а не эмулироваться атрибутами.


Принцип воспринимаемости (Perceivable)

Интерфейс должен быть представлен пользователю в форме, которую он способен воспринять.

Текстовые альтернативы

Любой нетекстовый контент обязан иметь текстовый эквивалент. Для изображений используется alt, для иконок — либо aria-label, либо скрытый текст.

<img src="logo.png" alt="Логотип компании" />

Декоративные изображения должны иметь пустой alt, чтобы скринридеры их игнорировали.

Контраст и цвет

Preact не управляет стилями напрямую, но архитектура компонентов влияет на соблюдение контрастности. Цвет не должен быть единственным способом передачи информации. Ошибки форм, статусы, уведомления должны сопровождаться текстом или иконками с альтернативным описанием.


Принцип управляемости (Operable)

Все элементы интерфейса обязаны быть доступны с клавиатуры.

Фокус и порядок навигации

В Preact фокус часто ломается из-за условного рендеринга. При монтировании и размонтировании компонентов необходимо контролировать, куда переходит фокус.

const ref = useRef(null);

useEffect(() => {
  ref.current?.focus();
}, []);

return <button ref={ref}>Подтвердить</button>;

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

Использование нативных элементов

<button> всегда предпочтительнее <div onClick>. Нативные элементы автоматически поддерживают клавиатуру, фокус и роли доступности.

Плохо:

<div onCl ick={submit}>Отправить</div>

Хорошо:

<button onCl ick={submit}>Отправить</button>

Принцип понятности (Understandable)

Интерфейс должен быть логичным и предсказуемым.

Подписи и формы

Каждое поле ввода обязано иметь связанную подпись. Связь достигается через label и htmlFor.

<label htmlFor="email">Email</label>
<input id="email" type="email" />

Placeholder не заменяет label, так как исчезает при вводе и плохо читается скринридерами.

Ошибки и сообщения

Сообщения об ошибках должны быть текстовыми и программно доступными. При динамическом появлении ошибок необходимо уведомлять вспомогательные технологии.

<div role="alert">Поле обязательно для заполнения</div>

Принцип надёжности (Robust)

Контент должен корректно работать с различными пользовательскими агентами и вспомогательными технологиями.

ARIA: только при необходимости

ARIA-атрибуты используются исключительно тогда, когда семантический HTML не решает задачу. Избыточное применение role, aria-* приводит к конфликтам.

Пример оправданного использования:

<div role="dialog" aria-modal="true" aria-labelledby="title">
  <h2 id="title">Настройки</h2>
</div>

Если компонент можно реализовать через <dialog>, ARIA не требуется.

Стабильность DOM

Частые перестроения DOM-дерева мешают скринридерам. В Preact важно избегать лишних перерисовок и резких изменений структуры.

Ключи (key) в списках обязательны не только для производительности, но и для предсказуемости доступности.

items.map(item => (
  <li key={item.id}>{item.name}</li>
))

Доступность и управление состоянием

Состояние интерфейса должно отражаться не только визуально, но и программно.

Пример переключателя:

<button
  aria-pressed={isOn}
  onCl ick={() => setIsOn(!isOn)}
>
  {isOn ? 'Включено' : 'Выключено'}
</button>

aria-pressed сообщает текущее состояние вспомогательным технологиям, синхронизируя UI и логику.


Работа с динамическим контентом

SPA-приложения на Preact часто обновляют контент без перезагрузки страницы. Это нарушает ожидания скринридеров.

Живые области (aria-live)

Для уведомлений, которые появляются динамически:

<div aria-live="polite">
  {message}
</div>

polite подходит для ненавязчивых сообщений, assertive — для критических.

Заголовки и навигация

При смене представлений (роутинг) важно обновлять заголовки страниц (<h1>) и, при необходимости, вручную переводить фокус на начало нового контента.


Архитектура компонентов и доступность

Доступность закладывается на уровне архитектуры:

  • атомарные компоненты с понятным назначением;
  • единый компонент кнопки вместо десятков кастомных реализаций;
  • централизованные паттерны модальных окон, форм, уведомлений.

Компоненты должны быть доступны по умолчанию, без необходимости дорабатывать каждый экземпляр.


Тестирование доступности

Даже корректный код требует проверки. В экосистеме Preact применяются:

  • Lighthouse (Accessibility);
  • axe-core;
  • ручная проверка клавиатурой;
  • тестирование со скринридером.

Автоматические тесты выявляют лишь часть проблем, но архитектурные ошибки видны уже на уровне JSX.


Итоговая роль Preact в доступности

Preact не ограничивает доступность и не улучшает её автоматически. Он предоставляет минималистичную, предсказуемую среду, где соблюдение принципов веб-доступности полностью зависит от проектирования компонентов, корректной семантики и дисциплины разработки.