Почему Accessibility — это не про «галочку», а про реальных людей
Представьте: вы заходите на сайт, а кнопка «Купить» не нажимается. Или текст сливается с фоном, как хамелеон на асфальте. Для человека с плохим зрением или моторными нарушениями это не «баг», а ежедневная реальность. Accessibility (a11y) — это не модный тренд, а мост, который соединяет ваш код с миллионами пользователей.
В России, по данным ВОЗ, более 12 миллионов человек имеют инвалидность. А если добавить пожилых людей, временные ограничения (сломанная рука, яркое солнце) — аудитория, которая нуждается в доступности, становится колоссальной. PHP разработка с учётом Accessibility — это не только этично, но и выгодно: поисковики любят семантику, а пользователи — удобство.
В этой статье мы разберём, как внедрить принципы WCAG (Web Content Accessibility Guidelines) прямо в PHP-код. Без воды, с живыми примерами и готовыми решениями.
С чего начать: семантическая разметка и PHP
Многие думают, что Accessibility — это только про CSS и JavaScript. Но корень проблемы часто лежит в серверной части. PHP генерирует HTML, и если этот HTML «глухой» — никакой фронтенд не спасёт.
Правильные заголовки и структура
Скринридеры (программы чтения с экрана) ориентируются на заголовки. Если у вас на странице один <h1>, а потом сразу <h3> — это как книга, где после оглавления идёт сноска. Нарушается иерархия.
Плохой подход:
<?php
// Генерация контента без учёта семантики
echo '<div class="title">' . $title . '</div>';
echo '<div class="subtitle">' . $subtitle . '</div>';
?>
Хороший подход (Accessibility в PHP):
<?php
// Семантическая структура для скринридеров
echo '<h1>' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '</h1>';
echo '<h2>' . htmlspecialchars($subtitle, ENT_QUOTES, 'UTF-8') . '</h2>';
?>
Обратите внимание на htmlspecialchars() — это база безопасности и доступности. Спецсимволы в заголовках могут сломать разметку или быть неправильно прочитаны.
ARIA-атрибуты: когда HTML не хватает
ARIA (Accessible Rich Internet Applications) — это набор атрибутов, которые дополняют семантику. Например, если вы делаете кастомный выпадающий список на PHP и JavaScript, скринридеру нужно сказать: «Эй, это кнопка, которая открывает меню».
Пример генерации ARIA-совместимой кнопки:
<?php
function renderAccessibleButton(string $label, string $id): string {
return sprintf(
'<button id="%s" aria-expanded="false" aria-controls="menu-%s">%s</button>',
htmlspecialchars($id),
htmlspecialchars($id),
htmlspecialchars($label)
);
}
echo renderAccessibleButton('Меню', 'main-menu');
?>
Атрибут aria-expanded сообщает скринридеру, открыто ли меню. aria-controls связывает кнопку с выпадающим блоком. Это как GPS-навигатор для незрячего пользователя.
Работа с формами: ловушка для Accessibility
Формы — самое больное место. Пользователь заполняет поле, а скринридер говорит: «Редактирование текста». Какого текста? Для чего? Без меток — это казино.
Связываем label и input
В PHP вы часто генерируете поля динамически. Главное правило: каждый <input> должен иметь <label> с атрибутом for, или сам input должен быть обёрнут в label.
Пример для динамической формы:
<?php
$fields = [
'name' => 'Имя',
'email' => 'Email',
'phone' => 'Телефон'
];
foreach ($fields as $key => $label):
?>
<div class="form-group">
<label for="input-<?= $key ?>"><?= htmlspecialchars($label) ?></label>
<input type="text" id="input-<?= $key ?>" name="<?= $key ?>" required>
</div>
<?php endforeach; ?>
Обратите внимание: id и for должны совпадать. Это не просто стиль — это закон для скринридеров.
Обработка ошибок с атрибутами
Когда пользователь вводит неверные данные, сообщение об ошибке должно быть связано с полем. Используйте aria-describedby:
<?php
$error = 'Введите корректный email';
echo '<input type="email" id="email" aria-describedby="email-error">';
echo '<span id="email-error" role="alert">' . htmlspecialchars($error) . '</span>';
?>
Атрибут role="alert" заставит скринридер немедленно прочитать ошибку, не дожидаясь, пока пользователь дойдёт до этого места.
Контрастность и цвета: не только CSS
Казалось бы, это задача дизайнера. Но если вы генерируете стили прямо из PHP (например, для кастомизации темы), нужно следить за контрастом. WCAG требует минимум 4.5:1 для обычного текста и 3:1 для крупного.
Пример проверки контрастности на PHP:
<?php
function getLuminance(string $hexColor): float {
$hex = ltrim($hexColor, '#');
$r = hexdec(substr($hex, 0, 2)) / 255;
$g = hexdec(substr($hex, 2, 2)) / 255;
$b = hexdec(substr($hex, 4, 2)) / 255;
// Применяем формулу относительной яркости
$r = ($r <= 0.03928) ? $r / 12.92 : pow(($r + 0.055) / 1.055, 2.4);
$g = ($g <= 0.03928) ? $g / 12.92 : pow(($g + 0.055) / 1.055, 2.4);
$b = ($b <= 0.03928) ? $b / 12.92 : pow(($b + 0.055) / 1.055, 2.4);
return 0.2126 * $r + 0.7152 * $g + 0