עץ הנגישות המלא בכלי הפיתוח ל-Chrome

Johan Bay
Johan Bay

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

מהו עץ הנגישות?

טכנולוגיה מסייעת, כמו קוראי מסך, משתמשת ב-API הנגישות של Chromium כדי לקיים אינטראקציה עם תוכן אינטרנט. המודל הבסיסי של ה-API הזה הוא עץ הנגישות: עץ של אובייקטים של נגישות שטכנולוגיה מסייעת יכולה להריץ בו שאילתות לגבי מאפיינים ומאפיינים משניים ולבצע בו פעולות. מפתחי אתרים מעצבים ומפעילים שינויים בעץ הנגישות בעיקר באמצעות מאפייני DOM, כמו מאפייני ARIA ל-HTML.

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

חלונית הנגישות של כלי הפיתוח ל-Chrome.

איך נוצר העץ?

לפני שנראה איך נראית תצוגת העץ המלאה החדשה ב-DevTools, ננסה להסביר בקצרה מהו עץ הנגישות במונחים מוחשי יותר. עץ הנגישות הוא נגזרת של עץ ה-DOM. המבנה שלו דומה, אבל פשוט יותר כדי להסיר צמתים ללא תוכן סמנטי, כמו רכיב <div> שמשמש רק לצורך עיצוב. לכל צומת בעץ יש תפקיד כמו Button או Heading, ולעיתים קרובות שם יכול להיות על בסיס מאפייני ARIA או על תוכן שנגזר מתוכן הצומת. אם אנחנו מסתכלים על מסמך HTML:

<html>
<head>
  <title>How old are you?</title>
</head>
<body>
  <label for="age">Age</label>
  <input id="age" type="number" name="age" value="42">
  <div>
    <button>Back</button>
    <button>Next</button>
  </div>
</body>
</html>

המנגנון להצגת תוכן ב-Chromium, שנקרא Blink, יוצר עץ פנימי של נגישות באופן הבא, בערך.

role='rootWebArea' focusable name='How old are you?'
  role='genericContainer' ignored
    role='genericContainer' ignored
      role='labelText'
        role='staticText' name='Age'
      role='spinButton' editable focusable name='Age' value='42'
        role='genericContainer' editable
          role='staticText' editable name='42'
      role='genericContainer'
        role='button' focusable name='Back'
          role='staticText' name='Back'
        role='button' focusable name='Next'
          role='staticText' name='Next'

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

עץ נגישות מלא בכלי הפיתוח

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

עכשיו, אחרי שהסברנו איך פועל עץ הנגישות, אפשר להשתמש בכלי הפיתוח כדי לראות איך נראית תצוגת העץ החדשה. מסמך ה-HTML הבא עם כותרת, כותרת משנית ושני לחצנים משמש להצגת העץ.

<!DOCTYPE html>
<title>Test</title>
<h1>Heading for example page</h1>
<div>
  <button>Back</button>
  <button>Next</button>
</div>

בתצוגת העץ הקודמת, אפשר היה לבחון רק צומת אחד ואת אביו.

תצוגת העץ הקודמת ב-DevTools.

עכשיו, כשמפעילים או משביתים את העץ החדש, הוא מחליף את תצוגת עץ ה-DOM ומאפשר לראות את עץ הנגישות המלא של הדף:

תצוגת העץ החדשה ב-DevTools.

יצירת עץ ביעילות

כדי לשפר את הביצועים של העץ גם באתרים גדולים יותר, העץ נבנה בצורה עצלה בחזית (frontend) תוך כדי הניתוח שלו. אחרי שמרחיבים צומת בעץ, הילדים של הצמתים מאוחזרים דרך פרוטוקול Chrome DevTools‏ (CDP) והעץ נבנה מחדש.

עץ הנגישות החדש שבו מוצגת התוצאה לדף גדול.

בשידור חי

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

סיפורם של עצים רבים

בתיאור של מהו עץ הנגישות, למדתם איך Blink יוצרת עץ נגישות ל-DOM שהיא מבצעת רינדור שלו, וכיצד DevTools מאחזרת את העץ הזה דרך CDP. זה נכון, אבל השמטנו כמה סיבוכים בתיאור הזה. למעשה, יש הרבה דרכים שונות להשתמש בעץ הנגישות ב-Chromium. בתהליך העיצוב של תצוגת העץ החדשה ב-DevTools, עשינו כמה בחירות לגבי החלק של הרכיבים הפנימיים של Chromium שרצינו להציג.

פלטפורמות

לכל פלטפורמה יש ממשק API שונה לנגישות. צורת העץ זהה בכל הפלטפורמות, אבל ממשק ה-API לאינטראקציה עם העץ שונה, ושמות המאפיינים יכולים להיות שונים. ב-DevTools מוצג העץ הפנימי של Chromium, שבו התפקידים והמאפיינים בדרך כלל תואמים לאלה שמוגדרים במפרט ARIA.

מספר מסגרות ובידוד של אתרים

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

צמתים שהמערכת מתעלמת מהם או לא מעניינת

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

תצוגת העץ החדשה עם כל הצמתים.

האזהרה הזאת היא שלמעשה, המשמעות היא שאנחנו צריכים לבנות עץ נוסף מזה שזמין בקצה העורפי. לדוגמה, נניח שיש לנו את הצמתים A, B, C ו-X שבהם A הוא צאצא X ו-B, ול-X יש את צאצא ג'. אם X הוא צומת שנדחה, אנחנו מסירים את X מהעץ ובמקום זאת יוצרים עץ שבו C הוא צאצא של A.

תרשים שמראה איך אנחנו מסורגים את העצים.

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

  • קל יותר לטפל בעדכוני צמתים מהקצה העורפי, כי יש לנו את אותו מבנה עץ בשתי נקודות הקצה. לדוגמה, אם הצומת B יוסר מהדוגמה, נקבל עדכון לצומת X (כי הצאצאים שלו השתנו), אבל אם נחסם את הצומת הזה, יהיה לנו קשה להבין מה צריך לעדכן.
  • הוא מבטיח שלכל צומתי ה-DOM יהיה צומת נגישות תואם. כשמפעילים את העץ, אנחנו בוחרים את הצומת התואם לצומת שנבחר כרגע בעץ ה-DOM. לדוגמה הקודמת, אם המשתמש מפעיל או משבית את העץ בזמן שצוין צומת ה-DOM התואם ל-X, אנחנו מזריקים את X בין הצמתים A ו-B ובוחרים את X בעץ. כך המשתמש יכול לבדוק את צומת הנגישות של כל צמתים DOM ולקבוע למה הצומת מתעלם.

רעיונות לעתיד

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

סינונים חלופיים

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

הדגשת בעיות A11y

נוכל לשלב ניתוח של 'שיטות מומלצות לנגישות' בעץ ולהדגיש בעיות נגישות ישירות בצמתים הבעייתיים.

הצגת פעולות בנושא נגישות בכלי הפיתוח

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