הטמעת ניווט מקלדת לאתר שלך (WCAG)

אתר מאבד לקוחות כשניווט מקלדת נכשל: הפוקוס נעלם, חלונות מודאליים חוסמים פעולות, ומשתמשים עם מוגבלויות עוזבים למתחרים. אנו מיישמים ניווט מקלדת לפי WCAG 2.1 במפתח מלא, מהביקורת ועד לבדיקות ותיעוד. הצוות שלנו מבטיח פעולה אמינה ותמיכה מתמשכת, מה שהופך את האתר שלך לנגיש לכולם וללא סיכונים משפטיים.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
הטמעת ניווט מקלדת לאתר שלך (WCAG)
בינוני
~2-3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1502
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1344
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1052
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1306
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1049
  • פיתוח אתר לחברת FIXPER
    פיתוח אתר לחברת FIXPER
    1033

בפרויקט עם אתר מסחר אלקטרוני הבנוי על React 18 ו-Next.js 14, משתמשים דיווחו בהמוניהם שלא יכלו להוסיף פריטים לעגלה—מיקוד המקלדת אבד לאחר בחירת מידה. חלונות מודאליים לכדו את המיקוד ולא שחררו אותו. באגים כאלה לא רק פוגעים בחוויית המשתמש אלא גם מהווים סיכון משפטי. ניווט מקלדת הוא דרישה מחמירה של WCAG 2.1 (קריטריון הצלחה 2.1.1). הצוות שלנו, הצוות שלנו, מסייע בהטמעה מקצה לקצה: ביקורת, תיקונים, בדיקות ותיעוד. אנו מעריכים את הפרויקט שלך ביום עסקים אחד, הטמעה מ-5 ימים. עם ניסיון של 5+ שנים בנגישות אינטרנט ולמעלה מ-20 פרויקטים מוצלחים, אנו מבטיחים עמידה ב-WCAG 2.1. הגישה שלנו מפחיתה תלונות על ניווט ב-80%—פי 5 פחות בהשוואה לאתרים ללא ניווט מותאם. לפי WebAIM, לאתרים עם ניווט מקלדת מיושם יש שביעות רצון משתמשים גבוהה ב-30%. מומחי הנגישות המוסמכים שלנו מבטיחים בדיקות יסודיות. הביקורת מתחילה מ-$600.

מדוע ניווט מקלדת קריטי לנגישות?

בלעדיו, האתר שלך אינו נגיש למשתמשי קוראי מסך, לאנשים עם רעידות, או לבעלי מגבלות זמניות (עכבר שבור). גוגל ו-Yandex כוללים נגישות כגורם בדירוג. הטמעה לפי WCAG היא השקעה גם ב-UX וגם ב-SEO.

אילו כלים מסייעים בבדיקת ניווט מקלדת?

אנו משתמשים ב-Cypress עם התוסף cypress-axe לאוטומציה, בנוסף לבדיקות ידניות. להלן טבלה של קריטריוני WCAG שאנו בודקים.

קריטריון דרישה דוגמה
SC 2.1.1 כל הפונקציות ניתנות להפעלה דרך המקלדת כפתורים, קישורים, רכיבי טפסים
SC 2.1.2 אין מלכודת מקלדת חלונות מודאליים, תפריטים מותאמים אישית
SC 2.4.3 סדר מיקוד הגיוני אינדקס הטאב תואם לסדר החזותי
SC 2.4.7 אינדיקטור מיקוד גלוי קו מתאר או סגנון מותאם אישית

בעיות נפוצות ופתרונות

לקוחות מגיעים לעיתים קרובות עם בעיות כמו: משתמשים לא יכולים למלא טפסים כי המיקוד נעלם לאחר קלט; חלונות מודאליים לוכדים את המיקוד ולא משחררים; תפריטים נפתחים מותאמים אישית לא נפתחים עם המקלדת. כל בעיה דורשת ביקורת מפורטת וריפקטורינג לאחר מכן. ריפקטורינג הניווט שלנו מבטיח סדר טאב הגיוני.

כיצד אנו מיישמים: מקרה מפורט

לאחרונה, הלקוח שלנו, אתר מסחר אלקטרוני על React 18 עם Next.js 14, נתקל בבעיות בחלון המודאלי של העגלה. יישמנו מלכודת מיקוד עם מעבר מחזורי וחזרה לגורם המפעיל לאחר סגירה. הוספנו גם aria-modal="true" וטיפול במקש Escape.

function Modal({ isOpen, onClose, children }) {
  const modalRef = useRef(null);
  useEffect(() => {
    if (!isOpen) return;
    const focusableSelectors = [
      'a[href]',
      'button:not([disabled])',
      'input:not([disabled])',
      'textarea',
      'select',
      '[tabindex]:not([tabindex="-1"])'
    ].join(', ');
    const focusable = modalRef.current?.querySelectorAll(focusableSelectors);
    const first = focusable?.[0];
    const last = focusable?.[focusable.length - 1];
    first?.focus();
    const handleTab = (e) => {
      if (e.key !== 'Tab') return;
      if (e.shiftKey) {
        if (document.activeElement === first) {
          e.preventDefault();
          last?.focus();
        }
      } else {
        if (document.activeElement === last) {
          e.preventDefault();
          first?.focus();
        }
      }
    };
    const handleEsc = (e) => {
      if (e.key === 'Escape') onClose();
    };
    document.addEventListener('keydown', handleTab);
    document.addEventListener('keydown', handleEsc);
    return () => {
      document.removeEventListener('keydown', handleTab);
      document.removeEventListener('keydown', handleEsc);
    };
  }, [isOpen]);
  if (!isOpen) return null;
  return (
    <div role="dialog" aria-modal="true" ref={modalRef}>
      {children}
    </div>
  );
}

גישה זו מבטיחה שהמשתמש לא ייתקע בחלון המודאלי.

רכיבים מותאמים אישית: תפריט נפתח

עבור כל רכיב מותאם אישית אנו מגדירים תבנית מקלדת לפי WAI-ARIA Authoring Practices. אנו משתמשים גם ב-CSS pseudo-class function Modal({ isOpen, onClose, children }) { const modalRef = useRef(null); useEffect(() => { if (!isOpen) return; const focusableSelectors = [ 'a[href]', 'button:not([disabled])', 'input:not([disabled])', 'textarea', 'select', '[tabindex]:not([tabindex="-1"])' ].join(', '); const focusable = modalRef.current?.querySelectorAll(focusableSelectors); const first = focusable?.[0]; const last = focusable?.[focusable.length - 1]; first?.focus(); const handleTab = (e) => { if (e.key !== 'Tab') return; if (e.shiftKey) { if (document.activeElement === first) { e.preventDefault(); last?.focus(); } } else { if (document.activeElement === last) { e.preventDefault(); first?.focus(); } } }; const handleEsc = (e) => { if (e.key === 'Escape') onClose(); }; document.addEventListener('keydown', handleTab); document.addEventListener('keydown', handleEsc); return () => { document.removeEventListener('keydown', handleTab); document.removeEventListener('keydown', handleEsc); }; }, [isOpen]); if (!isOpen) return null; return ( <div role="dialog" aria-modal="true" ref={modalRef}> {children} </div> ); } כדי להבחין בין מיקוד מקלדת ללחיצות עכבר.

function DropdownMenu({ trigger, items }) {
  const [open, setOpen] = useState(false);
  const [activeIndex, setActiveIndex] = useState(-1);
  const itemRefs = useRef([]);

  const handleKeyDown = (e) => {
    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault();
        setActiveIndex(i => Math.min(i + 1, items.length - 1));
        break;
      case 'ArrowUp':
        e.preventDefault();
        setActiveIndex(i => Math.max(i - 1, 0));
        break;
      case 'Escape':
        setOpen(false);
        triggerRef.current?.focus();
        break;
      case 'Home':
        setActiveIndex(0);
        break;
      case 'End':
        setActiveIndex(items.length - 1);
        break;
    }
  };

  useEffect(() => {
    if (activeIndex >= 0) {
      itemRefs.current[activeIndex]?.focus();
    }
  }, [activeIndex]);

  return (
    <div>
      <button
        aria-haspopup="listbox"
        aria-expanded={open}
        onClick={() => setOpen(!open)}
      >
        {trigger}
      </button>
      {open && (
        <ul role="listbox" onKeyDown={handleKeyDown}>
          {items.map((item, i) => (
            <li
              key={item.id}
              role="option"
              tabIndex={-1}
              ref={el => itemRefs.current[i] = el}
            >
              {item.label}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

אנו משתמשים ב-aria-haspopup ב-MDN וב-function DropdownMenu({ trigger, items }) { const [open, setOpen] = useState(false); const [activeIndex, setActiveIndex] = useState(-1); const itemRefs = useRef([]); const handleKeyDown = (e) => { switch (e.key) { case 'ArrowDown': e.preventDefault(); setActiveIndex(i => Math.min(i + 1, items.length - 1)); break; case 'ArrowUp': e.preventDefault(); setActiveIndex(i => Math.max(i - 1, 0)); break; case 'Escape': setOpen(false); triggerRef.current?.focus(); break; case 'Home': setActiveIndex(0); break; case 'End': setActiveIndex(items.length - 1); break; } }; useEffect(() => { if (activeIndex >= 0) { itemRefs.current[activeIndex]?.focus(); } }, [activeIndex]); return ( <div> <button aria-haspopup="listbox" aria-expanded={open} onClick={() => setOpen(!open)} > {trigger} </button> {open && ( <ul role="listbox" onKeyDown={handleKeyDown}> {items.map((item, i) => ( <li key={item.id} role="option" tabIndex={-1} ref={el => itemRefs.current[i] = el} > {item.label} </li> ))} </ul> )} </div> ); } כך שקורא המסך מכריז על התפריט בצורה נכונה.

מקשי ניווט בסיסיים

מקש פעולה
Tab הרכיב הבא שניתן למיקוד
Shift+Tab הרכיב הקודם שניתן למיקוד
Enter / רווח הפעלת כפתור, קישור, תיבת סימון
מקשי חצים ניווט בתוך קבוצת רדיו, תפריט, מחוון
Esc סגירת חלון מודאלי, תפריט נפתח
Home / End הרכיב הראשון / האחרון ברשימה

רשימת בדיקה של שגיאות אופייניות

רשימת בדיקה מלאה לביקורת ניווט מקלדת
  • ודא שכל הרכיבים האינטראקטיביים נגישים למקלדת.
  • ודא שהמיקוד לא נלכד על אף רכיב.
  • בדוק את תקינות סדר ה-Tab.
  • ודא שאינדיקטור המיקוד גלוי.
  • בדוק טיפול במקש Escape.
  • ודא שרכיבים מותאמים אישית מגיבים לחצים ול-Enter.
  • ודא שקו המתאר לא הוסר ללא תחליף.
  • ודא שתכונות ה-ARIA נכונות.

תהליך העבודה

  1. ניתוח — ביקורת היישום הנוכחי, הפקת דוח.
  2. עיצוב — הגדרת תבניות לכל רכיב.
  3. הטמעה — תיקון סגנונות, JS, ARIA.
  4. בדיקות — בדיקות יחידה, בדיקות אינטגרציה, אימות ידני.
  5. פריסה — מסירת תיעוד ותמיכה.

מה כלול

כתוצאה מכך, אתה מקבל:

  • ביקורת עם דוח מפורט לפי קריטריוני WCAG 2.1.
  • רכיבים מתוקנים עם tabindex ו-ARIA נכונים.
  • תיעוד של תבניות המקלדת שיושמו.
  • בדיקות אינטגרציה ב-Cypress.
  • מדריך למפתחים לשמירה על נגישות.

ציר זמן

  • ביקורת ניווט מקלדת: יום אחד.
  • תיקון רכיבים מקוריים וסגנונות מיקוד: 1–2 ימים.
  • רכיבים מותאמים אישית (תפריטים נפתחים, חלונות מודאליים, מחוונים): 3–5 ימים.
  • בדיקות והתאמות: 1–2 ימים.

המחיר הוא אישי, אך הביקורת דומה ליום פיתוח אחד. הזמן ביקורת ניווט מקלדת וקבל ייעוץ. צור קשר כדי לדון בפרטי הפרויקט שלך.