אתר סטנדרטי עם ניגודיות של 4.5:1 וגדלי גופנים ברירת מחדל הוא צעד בכיוון הנגישות, אך אינו מבטיח נוחות למשתמשים עם ליקויי ראייה או מוטוריים. מצב נגישות פותר זאת באופן מקיף: הוא מגדיל טקסט, מגביר ניגודיות ל-7:1, מבטל אנימציות ומגדיל אזורי לחיצה. יישמנו פתרון כזה באמצעות משתני CSS ורכיב React.
למה נגישות סטנדרטית לא מספיקה?
WCAG 2.1 דרישות הן המינימום. טקסט קטן מ-18px דורש ניגודיות של 4.5:1, אך משתמשים עם ראייה ירודה מעדיפים לעיתים קרובות 7:1 או יותר. בנוסף, נגישות סטנדרטית לא מתחשבת בהעדפות אישיות: חלק זקוקים רק לטקסט גדול, אחרים לניגודיות גבוהה, ויש הסובלים מאנימציות. המצב שלנו נותן בחירה: המשתמשים מחליטים אילו שיפורים להפעיל.
איך הפתרונות שלנו עובדים?
הבסיס הוא קבוצת משתני CSS שמוחלפים כאשר מוגדר מאפיין נתונים על html. זה מחיל שינויים באופן מיידי על כל הממשק. המעבר מתרחש ללא JavaScript — רק באמצעות CSS.
| אפשרות | משתנה CSS | השפעה |
|---|---|---|
| ניגודיות גבוהה | --color-text, --color-bg, --focus-outline |
ניגודיות טקסט ורקע של לפחות 7:1 |
| טקסט מוגדל | --font-size-base |
גודל גופן בסיסי גדל ב-4px |
| הפחתת תנועה | --transition-duration ו-animation-duration: 0.01ms |
כל האנימציות והמעברים מושבתים |
| אזורי מגע גדולים יותר | --min-touch-target ל-56px |
כפתורים וקישורים הופכים לגדולים יותר, קלים יותר לשימוש עבור ליקויים מוטוריים |
רכיב בקרת React
כתבנו useAccessibilityMode hook שמאחסן מצבים נבחרים ב-localStorage ומאזין לשאילתות מדיה של המערכת. אם מערכת ההפעלה מוגדרת להפחתת תנועה, מצב reduced-motion מופעל אוטומטית.
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)
חלק מהשיפורים מוחלים אוטומטית אם המשתמש הגדיר את מערכת ההפעלה שלו. שאילתות מדיה של CSS מחליפות משתנים עבור 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> ); } , prefers-reduced-motion: reduce ו-prefers-contrast: more. זה מפחית עומס על הדפדפן וחוסך רוחב פס — אין צורך ב-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;
}
} מה כלול ביישום מצב הנגישות?
תוצרים:
- קבוצת משתני CSS המותאמים לעיצוב שלך
- רכיב React עם פאנל בקרה
- אינטגרציה אוטומטית עם הגדרות מערכת (prefers-*)
- תיעוד לתחזוקה והגדרה
- מדריך משתמש לשימוש במצב
אנחנו גם מאמנים את הצוות שלך: אנו מראים כיצד להוסיף אפשרויות חדשות ולבדוק נגישות. לצוות שלנו ניסיון של למעלה מ-5 שנים בנגישות אתרים והוא השלים יותר מ-30 פרויקטים.
תהליך היישום
| שלב | משך | תיאור |
|---|---|---|
| ביקורת נגישות נוכחית | יום אחד | בדיקת ניגודיות, גודל טקסט, פוקוס, תפעול מקלדת |
| עיצוב משתני CSS | יום אחד | יצירת מערכת לעיצוב שלך |
| פיתוח רכיב | 1–2 ימים | כתיבת רכיב React או התאמה לארכיטקטורה שלך |
| בדיקות | יום אחד | בדיקת כל מצב עם קוראי מסך (NVDA, VoiceOver) ומקלדת |
| פריסה ותיעוד | 0.5 יום | מסירת קוד והוראות הגדרה |
לוח זמנים ועלות
היישום אורך 3 עד 5 ימים בהתאם למורכבות האתר. העלות מחושבת באופן אישי — נעריך את הפרויקט שלך. אנו מבטיחים שהמצב יעמוד בדרישות WCAG 2.1 רמה AA. גישת משתני ה-CSS שלנו מפחיתה את מאמץ התחזוקה פי 2, מה שהופך את היישום לחסכוני.
טעויות נפוצות במהלך היישום
- התעלמות משאילתות
prefers-color-scheme: darkשל המערכת — משתמשים צריכים לראות שינויים אוטומטית. - החלפת פוקוס רק ב-CSS ללא אינדיקטור גלוי — תמיד לשמור על קו מתאר גלוי.
- אין אפשרות איפוס — לתת למשתמשים אפשרות להחזיר את כל ההגדרות.
- שימוש רק ב-JavaScript למעבר — הפתרון עם משתני CSS מהיר פי 2–3 ואמין יותר.
איך להבטיח שהמצב עובד בכל הדפדפנים?
אנו בודקים בגרסאות העדכניות של Chrome, Firefox, Safari ו-Edge. משתני CSS נתמכים בכל הדפדפנים המודרניים, ושאילתות המדיה /* Автоматически для пользователей, выбравших уменьшение анимации в ОС */ @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; } } ו-prefers-* זמינות בגרסאות האחרונות. עבור דפדפנים ישנים יותר (IE11), קיימת ירידה הדרגתית: האתר נשאר נגיש אך ללא אפשרויות מורחבות.
סיכום
מצב נגישות אינו מותרות אלא הכרח עבור אתרים המיועדים לכל המשתמשים. צור קשר לייעוץ והערכת הפרויקט שלך. נעזור להפוך את האתר שלך לנגיש ונוח לכולם. קבל ביקורת נגישות וגלה כיצד לשפר את האתר שלך.







