ใช้ลำดับการอ่าน CSS เพื่อการนําทางโฟกัสตามลําดับเชิงตรรกะ

เผยแพร่: 1 พฤษภาคม 2025

พร็อพเพอร์ตี้ CSS reading-flow และ reading-order พร้อมใช้งานใน Chrome 137 โพสต์นี้จะอธิบายเหตุผลเบื้องหลังการออกแบบพร็อพเพอร์ตี้เหล่านี้และรายละเอียดคร่าวๆ เพื่อช่วยให้คุณเริ่มต้นใช้งาน

วิธีการจัดวาง เช่น ตารางกริดและ Flex ได้เปลี่ยนแปลงการพัฒนาส่วนหน้าไปอย่างมาก แต่ความยืดหยุ่นของวิธีการเหล่านี้อาจทำให้เกิดปัญหากับผู้ใช้บางราย การสร้างสถานการณ์ที่ลําดับภาพไม่ตรงกับลําดับแหล่งที่มาในลําดับ DOM นั้นทําได้ง่ายๆ เนื่องจากเบราว์เซอร์จะทําตามลําดับแหล่งที่มานี้หากคุณไปยังส่วนต่างๆ ของเว็บไซต์โดยใช้แป้นพิมพ์ ผู้ใช้บางรายจึงอาจพบการกระโดดไปมาโดยไม่คาดคิดขณะไปยังส่วนต่างๆ ของหน้า

เราได้ออกแบบและเพิ่มพร็อพเพอร์ตี้ reading-flow และ reading-order ลงในข้อกำหนดการแสดงผล CSS เพื่อพยายามแก้ปัญหานี้ที่แก้มาอย่างยาวนาน

reading-flow

พร็อพเพอร์ตี้ reading-flow CSS จะควบคุมลําดับที่องค์ประกอบในเลย์เอาต์ Flex, ตาราง หรือบล็อกจะแสดงต่อเครื่องมือการช่วยเหลือพิเศษ และวิธีที่องค์ประกอบเหล่านั้นได้รับโฟกัสโดยใช้วิธีการไปยังส่วนต่างๆ ตามลําดับ

โดยจะใช้ค่าคีย์เวิร์ด 1 ค่า โดยมีค่าเริ่มต้นเป็น normal ซึ่งจะคงลักษณะการเรียงลําดับองค์ประกอบตามลําดับ DOM หากต้องการใช้ภายในคอนเทนเนอร์ Flex ให้ตั้งค่าเป็น flex-visual หรือ flex-flow หากต้องการใช้ภายในคอนเทนเนอร์ตารางกริด ให้ตั้งค่าเป็น grid-rows, grid-columns หรือ grid-order

reading-order

พร็อพเพอร์ตี้ CSS reading-order ช่วยให้คุณลบล้างลําดับของรายการในคอนเทนเนอร์ขั้นตอนการอ่านด้วยตนเองได้ หากต้องการใช้พร็อพเพอร์ตี้นี้ภายในคอนเทนเนอร์ตารางกริด คอนเทนเนอร์ Flex หรือคอนเทนเนอร์บล็อก ให้ตั้งค่า reading-flow ในคอนเทนเนอร์เป็น source-order และตั้งค่า reading-order ของแต่ละรายการเป็นค่าจำนวนเต็ม

ตัวอย่างใน Flexbox

ตัวอย่างเช่น คุณอาจมีคอนเทนเนอร์เลย์เอาต์ Flex ที่มีองค์ประกอบ 3 รายการเรียงตามลําดับแถวย้อนกลับ และต้องการใช้พร็อพเพอร์ตี้ลําดับเพื่อสับเปลี่ยนลําดับนั้นใหม่

<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;
}

ตอนนี้ลําดับโฟกัสคือ 1, 3, 2 ซึ่งจะเหมือนกับลำดับภาพที่คุณจะเห็นหากอ่านภาษาอังกฤษจากซ้ายไปขวา

หากต้องการคงลําดับโฟกัสตามเดิมโดยเรียงจากหลังไปหน้า ให้ตั้งค่าดังนี้

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

ตอนนี้ลําดับโฟกัสจะเป็นลําดับ Flex แบบย้อนกลับ คือ 2, 3, 1 ในกรณีทั้ง 2 รูปแบบ ระบบจะพิจารณาพร็อพเพอร์ตี้ 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>

คุณต้องการให้รูปภาพเด็กคนที่ 5 ใช้พื้นที่มากที่สุดที่ด้านบนสุด ตามด้วยรูปภาพเด็กคนที่ 2 ตรงกลางตารางกริด ระบบจะวางองค์ประกอบย่อยอื่นๆ ทั้งหมดภายในตารางกริดโดยอัตโนมัติตามเทมเพลตคอลัมน์

.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 เพื่อค้นหาองค์ประกอบก่อนหน้าที่โฟกัสได้ รายการนี้ตามรายการในลําดับแหล่งที่มา: 1 ถึง 12

วิธีแก้ไขปัญหานี้ ให้ตั้งค่าพร็อพเพอร์ตี้ reading-flow ดังนี้

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

ตอนนี้ลําดับโฟกัสคือ 5, 1, 3, 2, 4, 6, 7, 8, 9, 10, 11, 12 โดยจะเรียงตามลำดับภาพทีละแถว

หากต้องการให้ขั้นตอนการอ่านเป็นไปตามลําดับคอลัมน์แทน ให้ใช้ค่าคีย์เวิร์ด grid-columns แทน ลำดับโฟกัสจึงกลายเป็น 5, 6, 9, 7, 10, 1, 2, 11, 3, 4, 8, 12

.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;
}

คอนเทนเนอร์บล็อกต่อไปนี้มี 5 รายการ ไม่มีกฎเลย์เอาต์ที่จะจัดเรียงองค์ประกอบใหม่จากลําดับแหล่งที่มา แต่มีรายการที่ควรเข้าชมก่อน 1 รายการซึ่งอยู่นอกลําดับ

<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 หากมีความคิดเห็นเกี่ยวกับแท็บอินเด็กซ์และลักษณะการกําหนดขอบเขตโฟกัสโดยเฉพาะ โปรดแจ้งปัญหาใน HTML WHATNOT GitHub Repo เราอยากทราบความคิดเห็นของคุณเกี่ยวกับฟีเจอร์นี้