מרחשוון

נגישות בסרגלי ניווט בוורדפרס

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

למה הסרגלים לא מונגשים כברירת מחדל של וורדפרס

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

אני חושב שזה לא רעיון טוב; ברוב הפעמים wp_nav_menu אינו תפריט במובן שאליו מתכוונים ב-ARIA. כש-ARIA מתאר אלמנט כתפריט, הוא יוצר שקילוּת לתפריט פונקציונלי המשפיע על העמוד הנוכחי, כמו מחליף ניגודיות, בחירת גודל גופן וכד’. כל אלמנט עם role של menubar אמור להיות סדרת אופציות המשפיעות כל העמוד הנוכחי, לא אפשרויות ניווט לעמודים אחרים. רשימת קישורים, שהיא השימוש הנפוץ ביותר של wp_nav_menu, מיוצגת בצורה הטובה ביותר ב-role של navigation ולא בזה של menu.

 

I don’t think that this is a good idea; most of the time, wp_nav_menu is not a menu in the ARIA sense. When ARIA describes an item as being a menu, it’s drawing an equivalency to a menu of functions that effect the current page, such as a contrast changer, font size selector, etc. Anything with a role of menubar should be a set of options that effect the current page, not options that navigate to other pages. A list of links, like wp_nav_menu most often is, is best represented by the “navigation” role, rather than the menu role.

אז מה נעשה פה היום?

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

See the Pen Accessible Navbar by Lea (@leac) on CodePen.

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

לעטוף את סרגל הניווט בתגית nav עם ה-role של navigation, ולהוסיף תיאור

עטיפת הסרגל בתגית nav קל מאוד לעשות כי פשוט עושים זאת מחוץ לקריאה ל-wp_nav_menu. אציין כי אמנם אכן נהוג להשתמש ב-nav לסימון תפריט, אבל לא כולם עושים זאת ואף חלק מהתבניות אינן משתמשות באלמנט זה, החלק היותר חשוב הינו role=navigation, שגם אותו נעשה כאן. בנוגע לתיאור התפריט, מכיוון שבאתרים לרוב יש יותר מתפריט אחד, לדוגמה תפריט צד או תפריטים בפוטר, נכון להוסיף לכל תבנית aria-label=nav_desc. לדוגמה, לתפריט הראשי לתת תיאור: aria-label="תפריט ראשי". לתפריט בפוטר התיאור המתאים הוא aria-label="תפריט בתחתית העמוד". בדוגמת הקוד שלפנינו כתבתי תפריט ראשי רק לשם הדגמה, וכמובן צריך להשתמש בפונקציות התרגום של וורדפרס כדי שזה ייכתב בשפת הממשק. יש לציין שככלל, המאפיין aria-label איננו חובה, אבל הוא כן דרך להגיע ליותר טכנולוגיות מסייעות וסוגי דפדפנים. הוא דרך לשתף יותר מידע לגבי מה שקורה בתוך האלמנט ומשפר את ההקראה בכך שהוא מאפשר לדעת איפה אתה נמצא, ומידע יעיל אינו לשווא.

<nav id="site-navigation" class="main-navigation" role="navigation" aria-label="<?php _e('Primary Navigation','themeName') ?>">
 <?php wp_nav_menu( array(
     'theme_location' => 'primary',
   ) );
 ?>
</nav>

לתת ל-ul הראשי את החוק role=menubar

את זה נעשה בקריאה לפונקציה wp_nav_menu. באמצעות הפרמטר items_wrap, וניתן לו את הערך <ul id="%1$s" class="%2$s" role="menubar">%3$s</ul>. האחוזים ימולאו ע”י הפונקציה wp_nav_menu:

 <?php wp_nav_menu( array(
     'theme_location' => 'primary',
     'items_wrap' => '<ul id="%1$s" class="%2$s" role="menubar">%3$s</ul>' ) );
 ?>

לתת לכל li בתפריט את החוק role=menuitem

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

  1. ליצור Class שיירש מ-Walker_Nav_Menu:
    class Aria_Walker_Nav_Menu extends Walker_Nav_Menu {
    
    }
    
  2. להעתיק את הפונקציה start_el במלואה מהקלאס המקורי:
    public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ){ }
  3. להוסיף את השורה הזאת:
    // Lea 2017/10 - Add role=menuitem
     $role = ' role=menuitem';
    לפני השורה:
    $output .= $indent . '<li' . $id . $class_names . '>';
  4. ואז להוסיף לשורה ההיא את $role:
    $output .= $indent . '<li' . $id . $class_names . $role . '>';
  5. בסוף, חשוב מאוד להודיע לסרגל הניווט הרלוונטי שעליו להשתמש ב-Walker שיצרנו. זאת נעשה כך בקריאה לפונקציה wp_nav_menu:
    <?php wp_nav_menu( array(
     'theme_location' => 'primary',
     'walker' => new Aria_Walker_Nav_Menu(), );
     ?>

זהו. אפשר לראות כאן את הקוד במלואו. בשביל שורה ורבע מעתיקים פונקציה שלמה. מתי יעשו hook שיאפשר לשלוט במצה שקורה ב-li?

יש לתת ל-ul שעוטף את תת התפריט role=menu במידה ויש משמעות לתתי תפריט.

גם את ההתאמה הזאת, להוסיף לתת התפריט את role=menu צריך לעשות ע”י דריסת פונקציה מהקלאס Walker –  הפעם מדובר בפונקציה start_lvl. השלב הראשון הוא כמו בסעיף הקודם – יצירת הקלאס (מובן שאם כבר יצרנו אותו בסעיף הקודם, אין צורך לעשות זאת שוב כאן אלא פשוט מוסיפים את הפונקציה start_lvl). השלב השני דומה רק שצריך לקחת את הפונקציה start_lvl במקום את start_el. שלבים 3 ו-4 שונים: בדריסה של הפונקציה הזאת, עושים את השינוי הבא: לפני השורה האחרונה, מוסיפים את ה-role, ומשתמשים בו בשורה האחרונה:

// Lea 2017/10 - Add role=menu to ul of submenu
 $role = ' role=menu';

$output .= "{$n}{$indent}<ul $class_names $role>{$n}";

ולבסוף, כמו בשלב 5 בסעיף הקודם, מודיעים לסרגל הניווט הרלוונטי שעליו להשתמש ב-Walker שיצרנו ע”י העברה לפונקציה wp_nav_menu את new Aria_Walker_Nav_Menu(). הקוד של זה נמצא כאן.

כשיש תתי תפריטים נפתחים, יש לתת להם מאפיינים של aria-haspopup=”true” ו-aria-expanded=”false”.

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

לינק בערבית – יש להוסיף תיאור בעברית.

באחד התפריטים באתר שלנו היה פריט שמקשר לאתר בשפה זרה (במקרה שלנו – לערבית). אמנם אין הנחיה שאומרת שיש לתאר לקורא מסך בשפת הממשק (במקרה שלנו – עברית) את הכתוב בשפה הזרה – זו תוספת יפה אבל אין חובה כזו – אבל החלטנו בכל זאת להוסיף תיאור שמכיל את התרגום. את התיאור הכנסנו בממשק הנהול של הפריט, ובקוד הכנסנו את התיאור לתוך span שייראה רק לקוראי מסך. במקרה הזה לא צריך לדרוס כלום אלא להשתמש בפילטר nav_menu_item_args. הפילטר מעביר את הפרמטר $args שמכיל בתוכו את המאפיין link_after ולשם אפשר להכניס דברים שרוצים שיופיעו בתוך התגית של הקישור. לכן הכנסנו בתוכו תגית span ונתנו לה את הקלאס screen-reader-text – שהוא הקלאס בפרויקט שלנו שמסתיר אלמנטים מדפדפנים ומשמיע אותם רק לקוראי מסך (ה-CSS של הקלאס הזה מופיע בהמשך) – וב-span הכנסנו את תיאור הפריט ע”י שליפה שלו מ-$item->description. אז זאת הפונקציה שתרוץ על הפילטר nav_menu_item_args. ותוסיף את התיאור של פריט התפריט:

add_filter( 'nav_menu_item_args', 'filter_nav_menu_item_args', 10, 3 );

// Add a span with the description hidden in it, for accesibilty
 function filter_nav_menu_item_args( $args, $item, $depth ){

    if ( $item->description ) {
        // since we want the span to be nested in the link, we add it to the link_after attribute
        $args->link_after = '<span class="screen-reader-text">' . esc_attr( $item->description ) . '</span>';
    }

    return $args;
}

וזה ה-CSS של הקלאס:

/* Text meant only for screen readers. */
.screen-reader-text {
     clip: rect(1px, 1px, 1px, 1px);
     position: absolute !important;
     height: 1px;
     width: 1px;
     overflow: hidden; 
}
 .screen-reader-text:focus {
     background-color: #f1f1f1;
     border-radius: 3px;
     box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
     clip: auto !important;
     color: #21759b;
     display: block;
     font-size: 14px;
     font-size: 0.875rem;
     font-weight: bold;
     height: auto;
     left: 5px;
     line-height: normal;
     padding: 15px 23px 14px;
     text-decoration: none;
     top: 5px;
     width: auto;
     z-index: 100000;
 /* Above WP toolbar. */ 
}

בלי קשר לתפריט או לא, חובה לסמן שפות שונות משפת הממשק, קרי – אם יש טקסטים שונים יש להוסיף להם span lang=lang code direction=rtl/ltr, וכמו כן קישורים אשר מפנים לעמודים בשפות השונות מהשפה הנוכחית יש להוסיף להם hreflang=lang_code. את זה עשינו בממשק הניהול של התפריט – פשוט כתבנו את ה-span בפריט עצמו:

עטפנו את הכיתוב בערבית ב-span עם המאפיינים lang ו-hreflang. לא היה צורך ב-direction משום שערבית ועברית הן בעלות אותה כיווניות

להוסיף התראה על פתיחה בחלון חדש

אם ברצוננו להוסיף התראה לכל קישור בתפריט שנפתח בחלון חדש, אפשר לעשות זאת באותה פונקציה שיושבת על הפילטר nav_menu_item_args. נבדוק אם הקישור נפתח בחלון חדש ע”י בדיקת $item->target. אם הוא שווה _blank נוסיף span עם הכיתוב “(נפתח בחלון חדש)”, כמו שמבקשים בספסיפיקציה של הנגישות. יש שאלה ב-WPSE שבה ענו להשתמש בפילטר של nav_menu_item_title, רק שתדעו. אני משום מה העדפתי את הפילטר שבחרתי :O .

add_filter( 'nav_menu_item_args', 'filter_nav_menu_item_args', 10, 3 );

/**
 * Add a span with a warning that the link opens in new window when the link has a target equal to _blank, for accesibilty
 */
 function filter_nav_menu_item_args( $args, $item, $depth ){
 
    if ( $item->target == '_blank' ) {
        $args->link_after = '<span class="new-window-link">(' . __( 'opens in new window', 'motnet' ) . ') </span>';
    }

    return $args;
 }

קריאה נוספת

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

כתבו תגובה

כתובת הדוא"ל שלכם לא תוצג.