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

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

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

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

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

reading-flow

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

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

reading-order

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

דוגמה ב-Flexbox

לדוגמה, יכול להיות שיש לכם מאגר בפריסה גמישה עם שלושה רכיבים בסדר שורות הפוך, ואתם רוצים גם להשתמש במאפיין 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 כדי למצוא את הרכיב הקודם שאפשר להתמקד בו. הפריטים מופיעים לפי סדר המקור: אחד, שתיים, שלוש.

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

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

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

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

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

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

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

דוגמה לפריסת רשת

כדי להבין איך זה עובד בפריסת רשת, נניח שאתם יוצרים פריסה עם פריטים שממוקמים באופן אוטומטי ב-CSS grid עם 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. סדר המיקוד יהיה: חמישה, שש, תשע, שבע, עשר, אחת, שתיים, אחת עשרה, שלוש, ארבע, שמונה, שתים עשרה.

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

אפשר גם לנסות להשתמש ב-grid-order. סדר המיקוד יישאר אחד עד שנים עשר. הסיבה לכך היא שלא הגדרתם סדר 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.

בדוגמה הקודמת של flex, כדי לקבל את אותה תוצאה כמו באמצעות 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 וההתנהגות של היקף המיקוד, תוכלו לשלוח אותו כבעיה במאגר GitHub של HTML WHATNOT. נשמח לקבל ממך משוב על התכונה הזו.