Реалізація підтримки VoiceOver/Screen Reader для сайту (WCAG)

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація підтримки VoiceOver/Screen Reader для сайту (WCAG)
Середня
~3-5 робочих днів
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація підтримки VoiceOver/Screen Reader (WCAG)

Екранна читалка — програмне забезпечення, яке озвучує вміст сторінки для сліпих та слабозорих користувачів. VoiceOver (macOS/iOS), NVDA та JAWS (Windows), TalkBack (Android) оголошують вміст сторінки та забезпечують навігацію клавіатурою. WCAG 2.1 рівень AA вимагає повної доступності для екранних читалок.

Як працюють екранні читалки

Екранні читалки читають DOM-дерево та використовують Accessibility Tree — спеціальне представлення сторінки, побудоване з HTML та ARIA-атрибутів. Користувачі навігують за допомогою заголовків (H1-H6), посилань, форм та таблиць за допомогою спеціальних клавіатурних скорочень.

Базові вимоги

Семантична розмітка замість div-soup:

<!-- Погано -->
<div class="header">
  <div class="nav">
    <div class="nav-item" onclick="go('/home')">Домашня</div>
  </div>
</div>

<!-- Добре -->
<header>
  <nav aria-label="Основна навігація">
    <ul>
      <li><a href="/home">Домашня</a></li>
    </ul>
  </nav>
</header>

Орієнтири для навігації:

<header>...</header>
<nav aria-label="Основна навігація">...</nav>
<main>
  <article>...</article>
  <aside aria-label="Пов'язаний контент">...</aside>
</main>
<footer>...</footer>

Форми

<!-- Кожне поле форми повинно мати мітку -->
<label for="email">Email</label>
<input type="email" id="email" name="email"
       aria-describedby="email-hint email-error"
       aria-required="true">
<span id="email-hint" class="hint">Ми не будемо надсилати спам</span>
<span id="email-error" role="alert" aria-live="polite"></span>

<!-- Згруповані поля -->
<fieldset>
  <legend>Спосіб оплати</legend>
  <label><input type="radio" name="payment" value="card"> Карта</label>
  <label><input type="radio" name="payment" value="cash"> Готівка</label>
</fieldset>

Динамічний вміст та SPA

Основна проблема для екранних читалок у SPA — динамічні оновлення DOM не оголошуються автоматично.

// React — оголошення завантаження даних
function DataSection({ isLoading, data }) {
    return (
        <section>
            {/* aria-live для оголошення змін */}
            <div aria-live="polite" aria-atomic="true" className="sr-only">
                {isLoading ? 'Завантаження даних...' : 'Дані завантажені'}
            </div>

            {isLoading ? (
                <div aria-busy="true">
                    <span className="sr-only">Завантаження...</span>
                    <Spinner aria-hidden="true" />
                </div>
            ) : (
                <ul>
                    {data.map(item => <li key={item.id}>{item.title}</li>)}
                </ul>
            )}
        </section>
    );
}

Управління фокусом під час навігації

// При переході між сторінками в SPA — переміщення фокуса на заголовок сторінки
import { useEffect, useRef } from 'react';
import { useLocation } from 'react-router-dom';

function PageTitle({ title }) {
    const titleRef = useRef(null);
    const location = useLocation();

    useEffect(() => {
        titleRef.current?.focus();
        document.title = title;
    }, [location.pathname]);

    return (
        <h1 tabIndex={-1} ref={titleRef} className="focus-invisible">
            {title}
        </h1>
    );
}

Зображення та медіа

<!-- Інформаційне зображення -->
<img src="graph.png" alt="Діаграма зростання продажів: +35% у Q3 2024">

<!-- Декоративне зображення -->
<img src="decorative-bg.png" alt="" role="presentation">

<!-- Складна діаграма — додатковий текстовий опис -->
<figure>
    <img src="complex-chart.png" alt="Діаграма розподілу доходів"
         aria-describedby="chart-desc">
    <figcaption id="chart-desc">
        Діаграма показує: 40% доходів від продукту A, 35% від продукту B, 25% інше.
    </figcaption>
</figure>

Тестування екранної читалки

Інструменти:
- NVDA (Windows, безплатно) — найпоширеніша
- JAWS (Windows, комерційна) — корпоративний стандарт
- VoiceOver (macOS: Cmd+F5, iOS: потрійний клік Home)
- ChromeVox (Chrome розширення)

Автоматизоване тестування:
- axe-core — бібліотека для Playwright/Cypress
- jest-axe — для unit-тестів React компонентів
// Jest + jest-axe
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);

test('form is accessible', async () => {
    const { container } = render(<ContactForm />);
    const results = await axe(container);
    expect(results).toHaveNoViolations();
});

Часові рамки

  • Аудит поточного стану: 1–2 дні
  • Виправлення семантики та ARIA на існуючому проекті: 3–7 днів
  • Тестування екранної читалки + доводка: 2–3 дні