שימוש ב-CSS reading-flow לניווט לוגי רציף עם מיקוד

תאריך פרסום: 1 במאי 2025

המאפיינים reading-flow ו-reading-order של CSS זמינים מגרסה Chrome 137. בפוסט הזה נסביר את הסיבות לעיצוב של הנכסים האלה ונספק כמה פרטים שיעזרו לכם להתחיל להשתמש בהם.

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

המאפיינים reading-flow ו-reading-order תוכננו והוספו למפרט CSS Display כדי לנסות לפתור את הבעיה הזו שנמשכת כבר זמן רב.

reading-flow

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

היא מקבלת ערך מילת מפתח אחד, עם ברירת מחדל של normal, ששומרת על ההתנהגות של סידור רכיבים לפי סדר ה-DOM. כדי להשתמש בו בתוך קונטיינר flex, צריך להגדיר את הערך שלו ל-flex-visual או ל-flex-flow. כדי להשתמש בו בתוך מאגר רשת, צריך להגדיר את הערך שלו ל-grid-rows,‏ grid-columns או grid-order.

reading-order

המאפיין reading-order CSS מאפשר לכם לשנות באופן ידני את סדר הפריטים במאגר של זרימת קריאה. כדי להשתמש במאפיין הזה בתוך רשת, flex או מאגר בלוקים, צריך להגדיר את הערך reading-flow במאגר ל-source-order ולהגדיר את הערך reading-order של הפריט הבודד למספר שלם.

דוגמה ב-Flexbox

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

<div class="box">
 <a href="#">One</a>
 <a href="#">Two</a>
 <a href="#">Three</a>
</div>
.box {
  display: flex;
  flex-direction: row-reverse;
}

.box :nth-child(1) {
  order: 2;
}

אפשר לנסות לנווט בין האלמנטים האלה באמצעות המקש TAB כדי למצוא את האלמנט הבא שאפשר להתמקד בו, והמקשים TAB+SHIFT כדי למצוא את האלמנט הקודם שאפשר להתמקד בו. הסדר של הפריטים הוא כמו בסדר המקורי: One, ‏ Two, ‏ Three.

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

כדי לפתור את הבעיה, צריך להגדיר את הנכס reading-flow:

.box {
  reading-flow: flex-visual;
}

סדר המיקוד הוא עכשיו: 1, 3, 2. זה אותו סדר חזותי שמתקבל כשקוראים באנגלית משמאל לימין.

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

.box {
  reading-flow: flex-flow;
}

סדר המיקוד הוא עכשיו הסדר ההפוך של flex: ‏Two, ‏ Three, ‏ One. בשני המקרים, המאפיין order של שירות ה-CSS נלקח בחשבון.

דוגמה עם פריסת רשת

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

<div class="wrapper">
 <a href="#">One</a>
 <a href="#">Two</a>
 <a href="#">Three</a>
 <a href="#">Four</a>
 <a href="#">Five</a>
 <a href="#">Six</a>
 <a href="#">Seven</a>
 <a href="#">Eight</a>
 <a href="#">Nine</a>
 <a href="#">Ten</a>
 <a href="#">Eleven</a>
 <a href="#">Twelve</a>
</div>

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

.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
}
.wrapper a:nth-child(2) {
  grid-column: 3;
  grid-row: 2 / 4;
}
.wrapper a:nth-child(5) {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}

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

כדי לפתור את הבעיה, צריך להגדיר את הנכס reading-flow:

.wrapper {
  reading-flow: grid-rows;
}

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

אם רוצים שהקריאה תתבצע לפי סדר העמודות, אפשר להשתמש במקום זאת בערך מילת המפתח grid-columns. סדר המיקוד יהיה: Five,‏ Six, ‏ Nine, ‏ Seven, ‏ Ten, ‏ One, ‏ Two, ‏ Eleven, ‏ Three, ‏ Four, ‏ Eight, ‏ Twelve.

.wrapper {
  reading-flow: grid-columns;
}

אפשר גם לנסות להשתמש ב-grid-order. סדר המיקוד נשאר 1 עד 12. הסיבה לכך היא שלא הוגדרה הזמנה בשירות CSS לאף פריט.

קונטיינר חסימה באמצעות reading-order

המאפיין reading-order מאפשר לציין מתי צריך לבקר בפריט במהלך הקריאה, וכך לבטל את הסדר שמוגדר על ידי המאפיין reading-flow. היא משפיעה רק על מאגר תקין של זרימת קריאה, כשהמאפיין reading-flow לא normal.

.wrapper {
  display: block;
  reading-flow: source-order;
}

.top {
  reading-order: -1;
  inset-inline-start: 50px;
  inset-block-start: 50px;
}

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

<div class="wrapper">
  <a href="#">Item 1</a>
  <a href="#">Item 2</a>
  <a href="#">Item 3</a>
  <a href="#">Item 4</a>
  <a class="top" href="#">Item 5</a>
</div>

אם מגדירים את המאפיין reading-order של הפריט הזה לערך -1, סדר המיקוד יגיע אליו קודם, ואז יחזור לסדר המקור עבור שאר הפריטים בתהליך הקריאה.

דוגמאות נוספות זמינות באתר chrome.dev.

אינטראקציה עם tabindex

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

בדוגמה הקודמת של תוכנית גמישה, כדי לקבל את אותה תוצאה כמו השימוש ב-reading-flow: flex-visual, אפשר לבצע את הפעולות הבאות.

<div class="box" aria-owns="one three two">
  <a href="#" tabindex="1" id="one">One</a>
  <a href="#" tabindex="3" id="two">Two</a>
  <a href="#" tabindex="2" id="three">Three</a>
</div>

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

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

שימו לב: רכיב עם display: contents שמקבל בירושה את המאפיין reading-flow מרכיב ההורה של הפריסה יהיה גם הוא מאגר חוקי של זרימת קריאה. חשוב לזכור את זה כשמעצבים את האתר. מידע נוסף על הנושא הזה זמין בבקשה שלנו למשוב על reading-flow ועל display: contents.

חשוב לנו לדעת

אפשר לנסות את הדוגמאות שמופיעות בפוסט הזה ובדוגמאות של reading-flow ב-chrome.dev, ולהשתמש במאפייני ה-CSS האלה באתרים שלכם. אם יש לכם משוב, אתם יכולים להעלות אותו כבעיה במאגר GitHub של קבוצת העבודה בנושא CSS. אם יש לכם משוב ספציפי על ההתנהגות של tabindex ושל הגדרת היקף המיקוד, אתם יכולים להעלות אותו כבעיה במאגר HTML WHATNOT GitHub. נשמח לקבל משוב על התכונה הזו.