נגישות בריאקט

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

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

אז קודם כל – הנה ההרצאה – באנגלית במבטא בוראט איכותי – אפשר לצפות וגם לקרוא כי כתבתי פה גם את תמצית ההרצאה:

אז ראשית נגדיר את הבעיה – מה זו נגישות באופן כללי? נגישות זה לא רק שאנשים שמתקשים בראיה יוכלו להשתמש באתר או בממשק שלנו אלא נגישות זה גם לאנשים שיש להם בעיות מוטוריות – למשל אנשים מבוגרים או מתכנתים ישישים וממורמרים ששונאים נורא UI ומעדיפים להשתמש במקלדת, או אנשים שיש להם בעיות קשב וריכוז שממשק מקושקש מדי מפריע להם, או אפילו אנשים מתרבויות אחרות שחלק מהחיוויים לא מובנים להם (ידעתם שבבולגריה הנהון עם הראש משמעותו "לא"? והזזת הראש מצד לצד משמעותה "כן"?). כלומר נגישות זה עולם ומלואו.

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

אבל קל לזרוק "טוב, נבנה אתר נגיש", אבל איך בונים בכלל? האמת? זה קשה.

קומפוננטות נגישות קשות למימוש – דוגמה

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

גם מעבר לכך, זה קשה באמת. הדגמתי בהרצאה בחי מדקה 10 . לשם ההדגמה השתמשתי בתוסף קורא מסך שניתן להתקין על כרום פה. יש הרבה קוראי מסך וחלק גם במערכת ההפעלה. הוא קצת ישן אבל היתרון שלו הוא שהתוסף קל להתקנה ולהבנה. הראיתי איך אפילו בקומפוננטה פשוטה של טאבים יש בעיות נגישות קשות. הנה למשל הקומפוננטה. היא מאוד פשוטה (לא ריספונסיבית). אפשר להשתמש בה יופי:

See the Pen Untitled by Ran Bar-Zik (@barzik-the-vuer) on CodePen.

א-מ-מ-ה-? אם תנסו להשתמש בה עם מקלדת תאכלו קש. אז איך משתמשים בה עם מקלדת? נוסיף כמה שינויים של role ו-tab index שיעזרו לנו לנווט עם המקלדת:

const TabGroup = ({ types }) => {
  const [active, setActive] = useState(types[0]);
  return (
    <>
      <div role="tablist">
        {types.map((type) => (
          <Tab
            role="tab"
            tabIndex="0"
            key={type}
            active={active === type}
            onClick={() => setActive(type)}
          >
            {type}
          </Tab>
        ))}
      </div>
      <p role="presentation">The active content is !{active}</p>
    </>
  );
};

האם פתרנו את בעיית הנגישות? לא. כי כשאני מנווט (ואפשר לראות את זה בהרצאה) אני לא מצליח ללחוץ על אנטר כדי להפעיל את הטאב. למה? כי בחרתי באלמנט anchor שאליו צריך להוסיף href כדי להפוך אותו למופעל על ידי אנטר:

import React, { useState } from "react";
import Tab from "./Tab";

const TabGroup = ({ types }) => {
  const [active, setActive] = useState(types[0]);
  return (
    <>
      <div role="tablist">
        {types.map((type) => (
          <Tab
            role="tab"
            tabIndex="0"
            href="#"
            key={type}
            active={active === type}
            onClick={() => setActive(type)}
          >
            {type}
          </Tab>
        ))}
      </div>
      <p role="presentation">The active content is !{active}</p>
    </>
  );
};

export default TabGroup;

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

פתרון: ספרית קומפוננטות מוכנה

אם אנו רוצים לא לממש נגישות מאפס, אפשר בהחלט להשתמש בספרית קומפוננטות מוכנה כמו React Material UI שבאה כבר עם נגישות בילט אין. הבעיה היא שלא תמיד זה אפשרי (גם מבחינת הליגל של החברה או מבחינת המעצבים). הספריה הזו היא מאוד Opinionated עיצובית והתנהגותית ולמרות שאפשר להסיר או לשנות את העיצוב, יש התנגדויות פנימיות לזה. אז יש גם ספריה שכדאי להכיר שהיא כלל לא עיצובית אלא מכילה התנהגות נגישה בלבד שנקראת Reakit. אני אעטוף אותה עם העיצובים וההתנהגות שלי אבל היא כן תבטיח לי נגישות. ככה למשל אני אצור את ה-tab שלי עם Reakit:

import { useTabState, Tab, TabList, TabPanel } from "reakit/Tab";
import styled from "styled-components";

const StyledTab = styled(Tab)`
  background: white;
  border: 0;
  color: black;
  cursor: pointer;
  font-size: 20px;
  opacity: 0.6;
  outline: 0;
  padding: 10px 60px;
  text-decoration: none;
  &:focus {
    border: 3px solid black;
    opacity: 1;
  }
  ${({ active }) =>
    active &&
    `
  border-bottom: 2px solid black;
  opacity: 1;
`}
`;

const AriaKitTab = () => {
  const tab = useTabState();
  return (
    <>
      <TabList {...tab} aria-label="My tabs">
        <StyledTab {...tab}>Tab A</StyledTab>
        <StyledTab {...tab}>Tab B</StyledTab>
        <StyledTab {...tab}>Tab C</StyledTab>
      </TabList>
      <TabPanel {...tab}>The active content is Option A</TabPanel>
      <TabPanel {...tab}>The active content is Option B</TabPanel>
      <TabPanel {...tab}>The active content is Option C</TabPanel>
    </>
  );
};

export default AriaKitTab;

ושוב, בהרצאה ב-16:40 רואים איך אני מציג נגישות מושלמת.

אבל בניית קומפוננטות זה לא הכל

גם אם אני משתמש בקומפוננטות נגישות, אני יכול לעשות ממשק לא נגיש לחלוטין. איך? למשל אם אני משתמש בצבעים לא נכונים. איך אוכל לבדוק? יש כמה כלים. הבסיסי הוא Google Lighthouse שיש בכרום שמשתמש במנוע axe לבדיקת נגישות והראיתי בהרצאה איך מפעילים אותו (דקה 19). אבל יש כלי נוסף שיותר טוב לפי דעתי של DeQueue שגם הוא מגיע כתוסף על כרום ומומלץ מאוד לשימוש וגם אותו הדגמתי בהרצאה – בערך מדקה 20.

בדיקות אוטומטיות

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

import { render } from '@testing-library/react';
import TabGroup from './TabGroup';
import { axe, toHaveNoViolations } from 'jest-axe';

expect.extend(toHaveNoViolations)

const types = ['mockA', 'MockB'];

it('should have no a11y violations', async () => {
  render(<TabGroup types={types} />, document.body)
  const results = await axe(document.body)
  expect(results).toHaveNoViolations()
})

מדובר במודול jest ובבדיקה שיכולה להיות בכל קומפוננטה שמפתחים. רק חשוב לזכור שמה שנבדק זה ה-HTML המרונדר. לא שום דבר אחר אז אם יש שינויים בקומפוננטה (למשל דברים שמתווספים ב-HTML) אז חשוב לעשות אותם ואז להריץ את await axe(document.body) על התוצאה.

בבדיקת E2E, יש לנו את Cypress שעליו כתבתי לא מעט והפך להיות, נרצה או לא נרצה, ברירת המחדל בכל הנוגע לפרויקטים של פרונט אנד. יש לו תוסף נגישות ואני מדבר עליו בהרצאה מדקה 25 כולל דמו חי. הוא בודק, בדיוק כמו Google Lighthouse ו-DeQueue את הממשק בכללותו כולל צבעים. אך בניגוד אליהם הוא ניתן לשילוב בתשתית הבדיקות הקיימת. איך הקוד נראה? כך:

describe('A11Y spec', () => {
  it('passes', () => {
    cy.visit('http://localhost:3000');
    cy.injectAxe();
    cy.checkA11y();
  })
})

את הלינטר שמרתי לסוף ההרצאה. יש פלגין ל-eslint, שעושה בדיקות קוד סטטיות בבילד (מקומי או לא) בשם eslint-plugin-jsx-a11y. מאוד שימושי וכדאי להשתמש בו.

סיכום

בהרצאה הראיתי בעצם למה נגישות לבדה זה דבר ק-ש-ה. אבל יש כלי עזר – ראשית ברמה כתיבת הקוד: ספריות קומפוננטות יכולות מאוד לעזור. בזמן הפיתוח המפתחים יכולים לבדוק את הממשקים שלהם באמצעות תוספים שיש בדפדפני כרום. כדי לבצע בדיקות אוטומטיות בבילד – נשתמש ב-jest axe וב-Cypress E2E וכמובן שגם בלינטר.

את כל המאמצים והכלים האלו כדאי מאוד לתעד ב-README של הפרויקט ולתאם גם עם הליגל. כי כשמכתב התראה זה או אחר יגיע, והוא יגיע, יהיה לכם את כל המאמצים שלכם לוידוא נגישות ותוכלו לשלוף אותם ברגע.

פוסטים נוספים שכדאי לקרוא

למפתחי ובוני אתרי אינטרנט

מדריך לשאילתות יעילות ל Chat GPT

כל אחד יכול לשאול את GPT, אבל אם תרצו לשאול אותו שאלות על תכנות – יש כמה שיטות וטיפים ליעל את העבודה מולו.

צילום מסך של סוואגר
יסודות בתכנות

openAPI

שימוש בתשתית הפופולרית למיפוי ותיעוד של API וגם הסבר בסיסי על מה זה API

גלילה לראש העמוד