Screen reader поддержка

Slim.js — это минималистичная библиотека для создания веб-компонентов и реактивных интерфейсов на JavaScript. При разработке интерфейсов критически важно учитывать доступность (accessibility), включая поддержку screen reader для пользователей с нарушениями зрения. Slim.js не предоставляет встроенных инструментов для доступности, однако использование стандартов ARIA и правильная структура компонентов позволяет обеспечить полную совместимость с ассистивными технологиями.


Использование ARIA-атрибутов

Screen reader полагаются на ARIA (Accessible Rich Internet Applications) для интерпретации структуры и состояния интерфейса. Slim.js позволяет динамически добавлять атрибуты ARIA через bind-атрибуты.

Пример:

class ToggleButton extends Slim {
    isActive = false;

    toggle() {
        this.isActive = !this.isActive;
    }

    get template() {
        return `
            <button
                @click="toggle"
                aria-pressed="${this.isActive}"
                aria-label="Переключатель состояния"
            >
                ${this.isActive ? 'Вкл' : 'Выкл'}
            </button>
        `;
    }
}

Slim.tag('toggle-button', ToggleButton);

Особенности:

  • aria-pressed автоматически обновляется при изменении состояния кнопки.
  • aria-label обеспечивает читаемое имя для screen reader.
  • Обновления реактивны: изменение свойства isActive приводит к пересозданию DOM с актуальными атрибутами.

Динамическое управление фокусом

Для корректной работы screen reader важно управлять фокусом и его перемещением при динамических изменениях DOM. Slim.js предоставляет доступ к элементам через onAfterRender или напрямую через this.querySelector.

Пример управления фокусом при открытии модального окна:

class ModalDialog extends Slim {
    isOpen = false;

    open() {
        this.isOpen = true;
        this.update(); // триггер обновления DOM
    }

    onAfterRender() {
        if (this.isOpen) {
            const firstFocusable = this.querySelector('button, [tabindex]:not([tabindex="-1"])');
            firstFocusable?.focus();
        }
    }

    get template() {
        return this.isOpen ? `
            <div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
                <h2 id="dialog-title">Модальное окно</h2>
                <button @click="isOpen = false">Закрыть</button>
            </div>
        ` : '';
    }
}

Slim.tag('modal-dialog', ModalDialog);

Особенности:

  • role="dialog" сообщает screen reader о типе элемента.
  • aria-modal="true" блокирует взаимодействие с фоном.
  • Автоматическая установка фокуса на первый интерактивный элемент улучшает доступность.

Семантическая разметка компонентов

Screen reader лучше интерпретируют семантические HTML-элементы, чем элементы с нестандартными тегами. В Slim.js это важно учитывать при создании компонентов:

class AccessibleList extends Slim {
    items = ['Первый', 'Второй', 'Третий'];

    get template() {
        return `
            <ul>
                ${this.items.map(item => `<li>${item}</li>`).join('')}
            </ul>
        `;
    }
}

Slim.tag('accessible-list', AccessibleList);

Особенности:

  • Использование <ul> и <li> поддерживает навигацию для screen reader.
  • Избегание <div> без семантики для интерактивных элементов.

Live Regions и динамическое уведомление

Для уведомления пользователей о динамических событиях используется ARIA live regions (aria-live). Slim.js позволяет обновлять такие регионы реактивно.

Пример уведомлений:

class NotificationBar extends Slim {
    messages = [];

    addMessage(msg) {
        this.messages.push(msg);
        this.update();
    }

    get template() {
        return `
            <div aria-live="polite" role="status">
                ${this.messages.map(m => `<p>${m}</p>`).join('')}
            </div>
        `;
    }
}

Slim.tag('notification-bar', NotificationBar);

Особенности:

  • aria-live="polite" сообщает screen reader о новых уведомлениях без прерывания текущей речи.
  • role="status" усиливает значение уведомления как информационного.

Обработка клавиатуры

Screen reader часто взаимодействуют с интерфейсом через клавиатуру. Slim.js позволяет легко добавлять обработку событий keydown для компонентов:

class AccessibleTab extends Slim {
    activeIndex = 0;
    tabs = ['Tab 1', 'Tab 2', 'Tab 3'];

    onKeyDown(e) {
        if (e.key === 'ArrowRight') {
            this.activeIndex = (this.activeIndex + 1) % this.tabs.length;
            this.update();
        }
        if (e.key === 'ArrowLeft') {
            this.activeIndex = (this.activeIndex - 1 + this.tabs.length) % this.tabs.length;
            this.update();
        }
    }

    get template() {
        return `
            <div role="tablist" @keydown="onKeyDown">
                ${this.tabs.map((tab, i) => `
                    <button role="tab"
                            aria-selected="${i === this.activeIndex}"
                            tabindex="${i === this.activeIndex ? '0' : '-1'}">
                        ${tab}
                    </button>
                `).join('')}
            </div>
        `;
    }
}

Slim.tag('accessible-tab', AccessibleTab);

Особенности:

  • role="tablist" и role="tab" обеспечивают корректное восприятие списка вкладок.
  • aria-selected и tabindex управляют фокусом и текущим состоянием.
  • Обработка клавиш ArrowRight и ArrowLeft соответствует стандартам ARIA для вкладок.

Резюме по интеграции screen reader в Slim.js

  • Использование ARIA-атрибутов для описания состояния и ролей.
  • Поддержка фокуса и управление им через onAfterRender.
  • Семантическая разметка HTML для совместимости с ассистивными технологиями.
  • Live regions для динамических уведомлений.
  • Поддержка клавиатурной навигации для интерактивных компонентов.

Эти методы позволяют создавать полностью доступные компоненты в Slim.js без внешних библиотек. Грамотная комбинация реактивности и ARIA-атрибутов делает интерфейсы удобными для пользователей с любыми ограничениями.