שימוש באינדקס

שינוי סדר ה-DOM באמצעות Tabindex

Dave Gash
Dave Gash
Meggin Kearney
Meggin Kearney

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

תמיכה בדפדפן

  • 1
  • 12
  • 1.5
  • לא יותר מ-4

מקור

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

tabindex="0": הוספת רכיב לסדר הכרטיסיות הטבעי. ניתן להתמקד ברכיב על ידי לחיצה על המקש Tab, ולהתמקד באלמנט על ידי קריאה לשיטה focus() שלו.

<custom-button tabindex="0">Press Tab to Focus Me!</custom-button>

מקישים על Tab כדי להתמקד עכשיו.

tabindex="-1": מסיר רכיב מהסדר של הכרטיסיות הטבעיות, אבל עדיין אפשר להתמקד בו על ידי קריאה ל-method focus().

// TODO: DevSite - Code sample removed as it used inline event handlers

// TODO: DevSite - דוגמת הקוד הוסרה מכיוון שנעשה בה שימוש ברכיבי handler של אירועים מוטבעים

tabindex="5": כל אינדקס Tab גדול מ-0 מעביר את האלמנט לחלק הקדמי של סדר הכרטיסיות הטבעי. במקרה שיש מספר רכיבים שערך הטאב שלהם גדול מ-0, סדר הכרטיסיות מתחיל מהערך הנמוך ביותר שגדול מאפס וממשיך הלאה. שימוש במדד טאב גדול מ-0 נחשב לדפוס נגד.

<button>I should be first</button>
<button>And I should be second</button>
<button tabindex="5">But I jumped to the front!</button>

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

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

ניהול המיקוד ברמת הדף

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

במקרה כזה, כדאי לזהות את אזור התוכן שנבחר, לתת לו tabindex של 1- כדי שלא יופיע בסדר הכרטיסיות הטבעי, וקוראים ל-method focus. השיטה הזו, שנקראת ניהול המיקוד, מאפשרת לסנכרן בין ההקשר שבו המשתמש רואה את התוכן לבין התוכן החזותי באתר.

ניהול המיקוד ברכיבים

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

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

<!-- Focus the element using Tab and use the up/down arrow keys to navigate -->
<select>
    <option>Aisle seat</option>
    <option>Window seat</option>
    <option>No preference</option>
</select>

יכול להיות קשה לדעת אילו התנהגויות מקלדת ליישם, אבל יש מסמך מועיל שאפשר לעיין בו. במדריך Accessible Rich Internet Applications (ARIA) מפרט את סוגי הרכיבים והסוגים של פעולות המקלדת שהם תומכים בהם. נעסוק בהרחבה בהמשך על ARIA, אבל בינתיים נשתמש במדריך כדי לעזור להוסיף תמיכה במקלדת לרכיב חדש.

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

<radio-group>
    <radio-button>Water</radio-button>
    <radio-button>Coffee</radio-button>
    <radio-button>Tea</radio-button>
    <radio-button>Cola</radio-button>
    <radio-button>Ginger Ale</radio-button>
</radio-group>

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

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

קטע במפרט W3C עבור לחצני בחירה.

התכונה Tabindex פועלת על ידי הגדרת tabindex ל-1- עבור כל הילדים, מלבד החשבון שפעיל כרגע.

<radio-group>
    <radio-button tabindex="0">Water</radio-button>
    <radio-button tabindex="-1">Coffee</radio-button>
    <radio-button tabindex="-1">Tea</radio-button>
    <radio-button tabindex="-1">Cola</radio-button>
    <radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>

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

<radio-group>
    // Assuming the user pressed the down arrow, we'll focus the next available child
    <radio-button tabindex="-1">Water</radio-button>
    <radio-button tabindex="0">Coffee</radio-button> // call .focus() on this element
    <radio-button tabindex="-1">Tea</radio-button>
    <radio-button tabindex="-1">Cola</radio-button>
    <radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>

כשהמשתמש מגיע לילד או לילדה האחרון (או הראשון, בהתאם לכיוון שאליו מעבירים את המיקוד), אתם תעברו בחזרה בלולאה ותתמקדו לילד או לילדה הראשון (או האחרון) שוב.

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

מים קפה תה קולה ג'ינג'ר אייל

// TODO: DevSite - דוגמת הקוד הוסרה מכיוון שנעשה בה שימוש ברכיבי handler של אירועים מוטבעים

תוכלו לראות את המקור המלא של הרכיב הזה ב-GitHub.

ציורי קיר ומלכודות מקלדת

לפעמים כשאתה מנהל מיקוד, אתה עלול להיקלע למצב שאי אפשר לצאת ממנו. כדאי להשתמש בווידג'ט להשלמה אוטומטית שמנסה לנהל את המיקוד ותיעוד את התנהגות הכרטיסייה, אבל מונע מהמשתמש לצאת ממנו עד שיסתיים. פעולה זו נקראת מלכודת מקלדת, והיא יכולה להיות מתסכלת מאוד למשתמש. סעיף 2.1.2 ברשימת המשימות של Web AIM מטפל בבעיה הזו, ומציין שאסור לנעול או לתפוס את המיקוד של המקלדת ברכיב מסוים בדף. המשתמש צריך להיות מסוגל לנווט אל כל רכיבי הדף ואליהם באמצעות המקלדת בלבד.

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

חלון מודאלי שבו המשתמש מבקש לשמור את העבודה שלו.

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

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

מידע נוסף על <dialog> זמין במאמר על MDN, ובדוגמה הזו למודל מידע נוסף על חלונות מודאליים.

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

  1. באמצעות document.querySelector, בוחרים את רכיבי ה-div של חלון העזר ושכבת-העל ושומרים את ההפניות שלהם.
  2. עם פתיחת החלון, שומרים הפניה לרכיב שהיה מודגש בזמן הפתיחה, כדי שתוכלו להתמקד באותו רכיב.
  3. משתמשים ב-keydown listener כדי לתפוס מקשים כשלוחצים עליהם כשהחלון פתוח. תוכלו גם להאזין לקליק על שכבת-העל שברקע, ולסגור את החלון אם המשתמש לוחץ עליו.
  4. לאחר מכן, מקבלים את אוסף האלמנטים שניתן להתמקד בהם בתוך החלון. הרכיב הראשון והאחרון שניתן להתמקד בהם ישמשו כ "סנטינלים" כדי ליידע אתכם מתי להעביר את המיקוד קדימה או אחורה כדי להישאר בתוך החלון.
  5. הצגת חלון העזר והתמקדות ברכיב הראשון שניתן להתמקד בו.
  6. כשהמשתמש לוחץ על Tab או על Shift+Tab, מזיזים את המיקוד קדימה או אחורה, ומעבירים את המיקוד לרכיב האחרון או הראשון לפי הצורך.
  7. אם המשתמש מקיש על Esc, סוגרים את החלון הקופץ. זו שיטה שימושית מאוד כי היא מאפשרת למשתמש לסגור את החלון הקופץ בלי לחפש לחצן סגירה ספציפי, והוא מועיל גם למשתמשים בעכבר.
  8. כשסוגרים את החלון הקופץ, מסתירים אותו ואת שכבת-העל של הרקע ומשחזרים את המיקוד לרכיב הקודם שנשמר.

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

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