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

מפרץ יוהאן
יוהאן ביי

כלי הפיתוח ל-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>

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

תצוגת העץ הקודמת בכלי הפיתוח.

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

תצוגת העץ החדשה בכלי הפיתוח.

בניית עצים עצלנים

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

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

במצב פעיל

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

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

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

פלטפורמות

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

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

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

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

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

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

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

תרשים שמראה איך אנחנו גוזמים את העץ.

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

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

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

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

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

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

הדגשת בעיות הקשורות ל-A11y

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

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

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