Реализация режима повышенной доступности на сайте
Режим повышенной доступности — переключатель, который применяет набор дополнительных улучшений интерфейса: увеличенный шрифт, повышенный контраст, упрощённая анимация, улучшенные индикаторы фокуса. Позволяет не навязывать изменения всем пользователям, оставляя выбор за теми, кому это нужно.
Компоненты режима доступности
Типичный набор опций:
- Высококонтрастная тема (контраст 7:1+)
- Увеличенный шрифт (+2–4px базовый размер)
- Отключение анимации (
prefers-reduced-motion) - Увеличенные зоны кликабельности
- Более заметный индикатор фокуса
- Упрощённый layout (одна колонка)
CSS-переменные как основа
/* Базовые переменные */
:root {
--font-size-base: 16px;
--color-text: #333333;
--color-bg: #ffffff;
--color-accent: #0056b3;
--focus-outline: 2px solid #0056b3;
--focus-outline-offset: 2px;
--transition-duration: 300ms;
--min-touch-target: 44px;
}
/* Режим высокого контраста */
[data-accessibility-mode~="high-contrast"] {
--color-text: #000000;
--color-bg: #ffffff;
--color-accent: #0000CC;
--focus-outline: 3px solid #000000;
--focus-outline-offset: 4px;
}
/* Увеличенный шрифт */
[data-accessibility-mode~="large-text"] {
--font-size-base: 20px;
}
/* Уменьшение анимации */
[data-accessibility-mode~="reduced-motion"],
@media (prefers-reduced-motion: reduce) {
--transition-duration: 0ms;
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
/* Увеличенные цели касания */
[data-accessibility-mode~="large-targets"] {
--min-touch-target: 56px;
a, button, [role="button"] {
min-height: var(--min-touch-target);
min-width: var(--min-touch-target);
display: inline-flex;
align-items: center;
}
}
React-компонент управления режимом
type AccessibilityMode = 'high-contrast' | 'large-text' | 'reduced-motion' | 'large-targets';
function useAccessibilityMode() {
const [modes, setModes] = useState<Set<AccessibilityMode>>(() => {
const stored = localStorage.getItem('a11y-modes');
return stored ? new Set(JSON.parse(stored)) : new Set();
});
// Учитываем системные настройки
useEffect(() => {
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
if (mediaQuery.matches) {
setModes(prev => new Set([...prev, 'reduced-motion']));
}
}, []);
const toggle = useCallback((mode: AccessibilityMode) => {
setModes(prev => {
const next = new Set(prev);
next.has(mode) ? next.delete(mode) : next.add(mode);
localStorage.setItem('a11y-modes', JSON.stringify([...next]));
return next;
});
}, []);
// Применить к document.documentElement
useEffect(() => {
document.documentElement.dataset.accessibilityMode = [...modes].join(' ');
}, [modes]);
return { modes, toggle };
}
function AccessibilityPanel() {
const { modes, toggle } = useAccessibilityMode();
const [isOpen, setIsOpen] = useState(false);
const options = [
{ id: 'high-contrast' as const, label: 'Высокий контраст', icon: '◑' },
{ id: 'large-text' as const, label: 'Увеличенный текст', icon: 'A+' },
{ id: 'reduced-motion' as const, label: 'Меньше анимации', icon: '⏸' },
{ id: 'large-targets' as const, label: 'Крупные кнопки', icon: '⊞' },
];
return (
<div className="accessibility-widget">
<button
aria-expanded={isOpen}
aria-controls="a11y-panel"
onClick={() => setIsOpen(!isOpen)}
aria-label="Настройки доступности"
>
♿
</button>
{isOpen && (
<div id="a11y-panel" role="group" aria-label="Настройки доступности">
{options.map(opt => (
<label key={opt.id} className="a11y-option">
<input
type="checkbox"
checked={modes.has(opt.id)}
onChange={() => toggle(opt.id)}
/>
<span className="icon">{opt.icon}</span>
{opt.label}
</label>
))}
<button
onClick={() => {
localStorage.removeItem('a11y-modes');
setModes(new Set());
}}
>
Сбросить настройки
</button>
</div>
)}
</div>
);
}
Системные медиа-запросы (без JS)
Часть настроек применяется автоматически из системных настроек:
/* Автоматически для пользователей, выбравших уменьшение анимации в ОС */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Системная высококонтрастная тема */
@media (prefers-contrast: more) {
:root {
--color-text: #000;
--color-bg: #fff;
--focus-outline: 3px solid #000;
}
}
/* Тёмная тема */
@media (prefers-color-scheme: dark) {
:root {
--color-text: #f0f0f0;
--color-bg: #1a1a1a;
}
}
Позиционирование виджета
Виджет доступности обычно размещается в фиксированной позиции:
.accessibility-widget {
position: fixed;
bottom: 24px;
right: 24px;
z-index: 9000;
}
Важно: виджет сам должен быть доступен с клавиатуры — иначе пользователи, которым он нужен, не смогут им воспользоваться.
Срок реализации
3–5 дней: CSS-переменная система + React-компонент + тестирование каждого режима со screen reader.







