การใช้ Tabindex

การแก้ไขลำดับ DOM ด้วย Tabindex

ลำดับแท็บเริ่มต้นที่ตำแหน่ง 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 to Focus Me!

tabindex="-1": นำองค์ประกอบออกจากลำดับแท็บอย่างเป็นธรรมชาติ แต่จะยังโฟกัสองค์ประกอบได้ด้วยการเรียกใช้เมธอด focus()

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

// สิ่งที่ต้องทำ: DevSite - ตัวอย่างโค้ดถูกนำออกเนื่องจากใช้เครื่องจัดการเหตุการณ์แบบอินไลน์

tabindex="5": ดัชนีแท็บที่มากกว่า 0 จะข้ามองค์ประกอบไปหน้าลำดับแท็บปกติ หากมีหลายองค์ประกอบที่มีดัชนีแท็บมากกว่า 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 เพื่อให้เนื้อหาไม่ปรากฏในลำดับแท็บตามปกติ และเรียกใช้เมธอด 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 มีรายการรูปแบบการออกแบบ และในรายการดังกล่าวคือตารางลักษณะเฉพาะสำหรับกลุ่มวิทยุ ซึ่งเป็นคอมโพเนนต์ที่มีอยู่ซึ่งตรงกับองค์ประกอบใหม่มากที่สุด

อย่างที่เห็นในตาราง ลักษณะการทำงานของแป้นพิมพ์ทั่วไปอย่างหนึ่งที่ควรรองรับคือแป้นลูกศรขึ้น/ลง/ซ้าย/ขวา หากต้องการเพิ่มพฤติกรรมนี้ไปยังคอมโพเนนต์ใหม่ เราจะใช้เทคนิคที่เรียกว่า Roving Tabindex

ข้อกำหนด W3C ที่ตัดตอนมาสำหรับปุ่มตัวเลือก

ดัชนีแท็บ Roving ทำงานโดยการตั้งค่า 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>

จากนั้นคอมโพเนนต์จะใช้ Listener เหตุการณ์บนแป้นพิมพ์เพื่อระบุคีย์ที่ผู้ใช้กด เมื่อเกิดเหตุการณ์นี้ขึ้น คอมโพเนนต์ก็จะตั้งค่า 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>

เมื่อผู้ใช้ไปถึงรายการย่อยรายการสุดท้าย (หรือรายการแรก ขึ้นอยู่กับทิศทางที่ผู้ใช้ย้ายโฟกัส) คุณจะวนลูปและโฟกัสที่เด็กกลุ่มแรก (หรือสุดท้าย) อีกครั้ง

คุณสามารถดูตัวอย่างที่สมบูรณ์จากด้านล่างนี้ ตรวจสอบองค์ประกอบใน DevTools เพื่อดูว่า Tabindex ย้ายจากวิทยุหนึ่งไปยังอีกวิทยุหนึ่ง

น้ำ กาแฟ ชา โคลา Ginger Ale

// สิ่งที่ต้องทำ: DevSite - ตัวอย่างโค้ดถูกนำออกเนื่องจากใช้เครื่องจัดการเหตุการณ์แบบอินไลน์

คุณดูแหล่งที่มาทั้งหมดสำหรับองค์ประกอบนี้ได้ใน GitHub

วิธีการและกับดักแป้นพิมพ์

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

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

หน้าต่างโมดัลที่ขอให้ผู้ใช้บันทึกงาน

ในกรณีเช่นนี้ คุณสามารถใช้กับดักแป้นพิมพ์ชั่วคราวเพื่อตรวจจับโฟกัสเฉพาะในขณะที่โมดัลแสดงขึ้นเท่านั้น จากนั้นคืนค่าโฟกัสไปยังรายการที่โฟกัสก่อนหน้านี้เมื่อปิดโมดัล

มีข้อเสนอบางอย่างเกี่ยวกับวิธีทำให้การดำเนินการนี้ง่ายขึ้นสำหรับนักพัฒนาซอฟต์แวร์ ซึ่งรวมถึงองค์ประกอบ <dialog> แต่ยังไม่มีการรองรับเบราว์เซอร์อย่างแพร่หลาย

ดูข้อมูลเพิ่มเติมเกี่ยวกับ <dialog> ได้ที่บทความ MDN นี้และตัวอย่างโมดัลนี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับหน้าต่างโมดัล

ลองใช้กล่องโต้ตอบโมดัลที่แสดงด้วยdivซึ่งมีองค์ประกอบไม่กี่อย่าง และอีก div แสดงการวางซ้อนพื้นหลัง มาดูขั้นตอนพื้นฐานต่างๆ ที่จำเป็นในการ ติดตั้งกับดักแป้นพิมพ์ชั่วคราวในสถานการณ์นี้กัน

  1. เมื่อใช้ document.querySelector ให้เลือก div แบบโมดัลและการวางซ้อน แล้วจัดเก็บการอ้างอิง
  2. เมื่อโมดัลเปิดขึ้น ให้จัดเก็บการอ้างอิงไปยังองค์ประกอบที่โฟกัสไว้เมื่อโมดัลเปิดอยู่ เพื่อให้คุณกลับมาโฟกัสที่องค์ประกอบนั้นได้
  3. ใช้ Listener คีย์ดาวน์เพื่อจับคีย์ต่างๆ เมื่อมีการกดในขณะที่โมดัลเปิดอยู่ นอกจากนี้คุณยังสามารถฟังการคลิกบนพื้นหลังและ ปิดโมดัลหากผู้ใช้คลิกข้อความดังกล่าว
  4. ต่อไป ให้รับคอลเล็กชันขององค์ประกอบที่โฟกัสได้ภายในโมดัล องค์ประกอบแรกและองค์ประกอบสุดท้ายที่โฟกัสได้จะทำหน้าที่เป็น "เซนติเนล" เพื่อให้คุณทราบว่าเมื่อใดควรวนโฟกัสไปข้างหน้าหรือข้างหลังเพื่อให้อยู่ในโมดัลนี้
  5. แสดงหน้าต่างโมดัลและโฟกัสองค์ประกอบที่โฟกัสได้รายการแรก
  6. เมื่อผู้ใช้กด Tab หรือ Shift+Tab ให้เลื่อนโฟกัสไปข้างหน้าหรือข้างหลัง โดยวนซ้ำที่องค์ประกอบสุดท้ายหรือองค์ประกอบแรกตามความเหมาะสม
  7. หากผู้ใช้กด Esc ให้ปิดโมดัลนี้ การทำเช่นนี้มีประโยชน์มากเพราะช่วยให้ผู้ใช้ปิดโมดัลนี้ได้โดยไม่ต้องค้นหาปุ่มปิดที่เฉพาะเจาะจง และเป็นประโยชน์แม้แต่ผู้ใช้ที่กำลังใช้เมาส์
  8. เมื่อปิดโมดัลแล้ว ให้ซ่อนและการวางซ้อนพื้นหลัง แล้วคืนค่าโฟกัสไปยังองค์ประกอบที่โฟกัสก่อนหน้านี้ซึ่งบันทึกไว้ก่อนหน้านี้

กระบวนการนี้จะให้หน้าต่างโมดัลที่ใช้งานได้และไม่รบกวนการใช้งานที่ทุกคนใช้งานได้อย่างมีประสิทธิภาพ

ดูรายละเอียดเพิ่มเติมได้จากโค้ดตัวอย่างนี้และดูตัวอย่างจริงจากหน้าที่เสร็จสมบูรณ์แล้ว