คู่มือนักพัฒนาสำหรับ ARIA labels ที่ช่วยได้จริง
ARIA labels ไม่ใช่ชั้นการช่วยการเข้าถึงแบบวิเศษ ใช้อย่างเหมาะสมจะทำให้ control เข้าใจง่ายขึ้น ใช้อย่างลวก ๆ จะซ่อนข้อความที่มีประโยชน์และสร้าง interface ที่สับสน
สารบัญ
- ARIA labels มีไว้สำหรับชื่อ ไม่ใช่คำขอโทษ
- accessible name ในภาษาง่าย ๆ
- กฎข้อแรก: เลือก native HTML และ label ที่มองเห็นได้ก่อน
- เมื่อ `aria-label` เป็นเครื่องมือที่เหมาะสม
- เมื่อ `aria-label` เป็นเครื่องมือที่ผิด
- ใช้ `aria-labelledby` เมื่อมีข้อความที่มองเห็นได้อยู่แล้ว
- ใช้ `aria-describedby` สำหรับ help text ไม่ใช่ name
- control ที่ซ้ำกันต้องมีชื่อที่ไม่ซ้ำ
- อย่าใส่ label ให้ทุกอย่าง
- ตรวจสอบ computed name ไม่ใช่แค่ code
- checklist สำหรับ review ที่ใช้ได้จริง
- วินัยเงียบ ๆ ของ ARIA ที่ดี
ARIA labels มีไว้สำหรับชื่อ ไม่ใช่คำขอโทษ
ARIA มีประโยชน์ แต่มักถูกใช้เป็นแผ่นปะสำหรับ HTML ที่ไม่ชัดเจน และนั่นคือจุดที่ทีมมักเริ่มเจอปัญหา
ตัวอย่างที่พบบ่อยที่สุดคือ aria-label มันดูไม่เป็นอันตราย: เพิ่มสตริง สatisfy linter แล้วไปต่อ แต่ accessible name ไม่ใช่ของตกแต่ง มันคือชื่อที่เทคโนโลยีช่วยเหลือจำนวนมากแสดงให้ผู้ใช้เห็นเมื่อพวกเขานำทางตามปุ่ม ลิงก์ ฟิลด์ฟอร์ม heading, landmark และ control
ถ้าชื่อนั้นคลุมเครือ ซ้ำกัน ล้าสมัย หรือแตกต่างจาก label ที่มองเห็นได้ interface จะใช้งานยากขึ้น บางครั้งแย่กว่านั้น: aria-label สามารถ override ข้อความที่ดีกว่าซึ่งมีอยู่แล้วใน DOM ได้
เป้าหมายไม่ใช่การเพิ่ม ARIA ให้มากขึ้น เป้าหมายคือการทำให้ name, role, state และ purpose ของแต่ละองค์ประกอบใน interface ชัดเจน
accessible name ในภาษาง่าย ๆ
องค์ประกอบแบบโต้ตอบส่วนใหญ่มี accessible name Screen reader ใช้ชื่อนั้นเพื่อประกาศว่าองค์ประกอบนั้นคืออะไร
ตัวอย่างเช่น:
<button>Save changes</button>
Screen reader อาจประกาศประมาณว่า: “Save changes, button.” role มาจาก element button แบบ native ส่วน name มาจากข้อความข้างใน
นี่คือกรณีที่เหมาะที่สุด: ข้อความที่มองเห็นได้และ accessible name ตรงกัน
ARIA labeling attributes จะมีประโยชน์เมื่อ interface ที่มองเห็นได้ไม่ได้ให้ชื่อที่ครบถ้วน หรือเมื่อชื่อต้องมาจาก element อื่น attribute หลักคือ:
aria-label: ให้สตริงโดยตรงบน elementaria-labelledby: ชี้ไปยัง element หนึ่งรายการหรือมากกว่าที่ข้อความของมันจะกลายเป็น namearia-describedby: ชี้ไปยังข้อความคำอธิบายประกอบ ไม่ใช่ name หลัก
ทั้งสามอย่างเกี่ยวข้องกัน แต่ใช้แทนกันไม่ได้
กฎข้อแรก: เลือก native HTML และ label ที่มองเห็นได้ก่อน
ถ้าคุณใส่ข้อความที่มองเห็นได้บน control ได้ ให้ทำสิ่งนั้นก่อน
แบบนี้ดีกว่า:
<button>Delete invoice</button>
ดีกว่าแบบนี้:
<button aria-label="Delete invoice">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
รูปแบบที่สองใช้ได้สำหรับปุ่มที่มีเฉพาะไอคอน แต่ถ้า design รองรับข้อความที่มองเห็นได้ ข้อความที่มองเห็นได้ช่วยทุกคน: ผู้ใช้ screen reader, ผู้ใช้ speech recognition, คนที่มีภาระทางความคิดสูง, คนที่สแกนข้อมูลอย่างรวดเร็ว และคนที่ใช้เครื่องมือแปลภาษา
นี่เป็นประเด็นที่เกิดซ้ำในการทำงานด้าน accessibility Native HTML และ affordance ที่มองเห็นได้แก้ปัญหาได้มากกว่า metadata ที่ซ่อนอยู่ หลักการเดียวกันนี้ใช้กับ semantics ของปุ่มในภาพรวมด้วย หากทีมของคุณกำลัง audit UI controls checklist สำหรับปุ่มเว็บที่เข้าถึงได้ ของเราเป็นคู่มือประกอบที่ดีสำหรับบทความนี้
เมื่อ aria-label เป็นเครื่องมือที่เหมาะสม
ใช้ aria-label เมื่อ element ต้องการ accessible name และไม่มีข้อความที่มองเห็นได้ที่เหมาะสมให้ reference
กรณีคลาสสิกคือปุ่มที่มีเฉพาะไอคอน:
<button aria-label="Search">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<!-- icon -->
</svg>
</button>
สิ่งนี้สมเหตุสมผล ไอคอนที่มองเห็นได้สื่อถึงการค้นหา แต่ SVG path เองไม่ได้ให้ชื่อที่เชื่อถือได้ aria-label จึงเป็นตัวให้ชื่อนั้น
กรณีที่ดีอื่น ๆ ได้แก่:
- ปุ่มปิดที่แสดงด้วย “X” เท่านั้น
- navigation landmark ที่ต้องการชื่อเฉพาะเจาะจงมากขึ้น เช่น
aria-label="Product" - control ที่ซ้ำกันซึ่งบริบทที่มองเห็นได้ไม่ได้เป็นส่วนหนึ่งของข้อความบนปุ่ม
ตัวอย่างเช่น:
<nav aria-label="Primary">
...
</nav>
<nav aria-label="Footer">
...
</nav>
ทั้งคู่เป็น navigation landmarks แต่ label ช่วยให้ผู้ใช้แยกแยะได้เมื่อเคลื่อนที่ตาม landmarks
เมื่อ aria-label เป็นเครื่องมือที่ผิด
อย่าเพิ่ม aria-label เพียงเพราะ test บอกว่า element ต้องมี label ให้แก้ markup ก่อน
ไม่ดี:
<div role="button" tabindex="0" aria-label="Submit">Submit</div>
ดีกว่า:
<button>Submit</button>
ตัวอย่างแรกสร้างงานที่ไม่จำเป็น ตอนนี้คุณต้องสร้าง keyboard behavior, disabled states, form behavior และความคาดหวังที่ปุ่ม native มีให้พร้อมอยู่แล้วขึ้นมาใหม่
นอกจากนี้ควรหลีกเลี่ยงการใช้ aria-label เพื่อเปลี่ยนชื่อข้อความที่มองเห็นได้ในลักษณะที่เปลี่ยนความหมาย
<button aria-label="Delete invoice">Remove</button>
ดูเหมือนเป็นเรื่องเล็ก แต่สามารถทำให้ผู้ใช้ที่พึ่งพา speech input สับสนได้ ถ้าปุ่มที่มองเห็นได้เขียนว่า “Remove” แต่ accessible name คือ “Delete invoice” ผู้ใช้ที่พยายามพูดว่า “click Remove” อาจไม่ได้ผลลัพธ์ที่คาดหวัง ข้อกำหนด “label in name” ของ WCAG มีอยู่ด้วยเหตุผลนี้เอง: โดยทั่วไปข้อความที่มองเห็นได้ควรถูกบรรจุอยู่ใน accessible name
เวอร์ชันที่ดีกว่า:
<button aria-label="Remove invoice">Remove</button>
บ่อยครั้งแบบนี้ยังดีกว่า:
<button>Remove invoice</button>
ใช้ aria-labelledby เมื่อมีข้อความที่มองเห็นได้อยู่แล้ว
ถ้าข้อความ label มีอยู่แล้วบนหน้า aria-labelledby มักดีกว่า aria-label
ตัวอย่าง:
<h2 id="billing-title">Billing address</h2>
<section aria-labelledby="billing-title">
...
</section>
accessible name ของ section ตอนนี้มาจาก heading ที่มองเห็นได้ คุณหลีกเลี่ยงการทำสตริงซ้ำ ซึ่งลดข้อผิดพลาดในการแปลและ label ที่ล้าสมัย
สิ่งนี้มีประโยชน์เป็นพิเศษสำหรับกลุ่มฟอร์ม:
<fieldset aria-labelledby="shipping-speed-title">
<legend id="shipping-speed-title">Shipping speed</legend>
<label>
<input type="radio" name="shipping" value="standard">
Standard
</label>
<label>
<input type="radio" name="shipping" value="express">
Express
</label>
</fieldset>
ในหลายกรณี legend แบบ native ก็เพียงพอแล้วโดยไม่ต้องใช้ ARIA ประเด็นคือ label ที่มองเห็นได้ควรนำก่อน ARIA ควรเชื่อมความหมายที่มีอยู่ ไม่ใช่สร้างเวอร์ชันส่วนตัวชุดที่สองของมัน
ใช้ aria-describedby สำหรับ help text ไม่ใช่ name
คำอธิบายไม่ใช่ label
พิจารณาฟิลด์นี้:
<label for="password">Password</label>
<input id="password" type="password" aria-describedby="password-help">
<p id="password-help">Use at least 12 characters.</p>
accessible name คือ “Password” ส่วน description คือ “Use at least 12 characters.” Screen reader อาจประกาศทั้งสองอย่าง แต่ทั้งคู่ทำหน้าที่ต่างกัน
อย่าทำแบบนี้:
<input type="password" aria-label="Use at least 12 characters">
นั่นตั้งชื่อฟิลด์ตามคำแนะนำ ไม่ใช่ตามแนวคิดหลัก ผู้ใช้ที่นำทางฟอร์มต้องการรู้ก่อนว่าฟิลด์คืออะไร จากนั้นจึงค่อยรู้ว่ามีข้อจำกัดอะไรบ้าง
ความแตกต่างนี้สำคัญใน error states ด้วย:
<label for="email">Email</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
>
<p id="email-error">Enter an email address in the format [email protected].</p>
label ยังคงเสถียร ข้อความ error กลายเป็นบริบทสนับสนุน
control ที่ซ้ำกันต้องมีชื่อที่ไม่ซ้ำ
รายการและการ์ดคือพื้นที่ที่ ARIA labels มักจำเป็น
ไม่ดี:
<button>Delete</button>
<button>Delete</button>
<button>Delete</button>
ผู้ใช้ screen reader ที่นำทางตามปุ่มอาจได้ยิน “Delete, button” สามครั้งโดยไม่มีบริบท
ดี:
<button aria-label="Delete report: Q4 revenue">Delete</button>
<button aria-label="Delete report: Hiring plan">Delete</button>
<button aria-label="Delete report: Vendor list">Delete</button>
นี่เป็นการใช้ aria-label ที่ถูกต้อง: ข้อความที่มองเห็นได้ยังคงกระชับ ขณะที่ accessible name รวม object เข้าไปด้วย
แต่ใช้รูปแบบนี้อย่างระมัดระวัง หากชื่อ object มองเห็นได้อยู่ใกล้ ๆ aria-labelledby อาจดูแลรักษาง่ายกว่า:
<article>
<h3 id="report-q4">Q4 revenue</h3>
<button aria-labelledby="delete-q4 report-q4" id="delete-q4">Delete</button>
</article>
accessible name จะกลายเป็น “Delete Q4 revenue.” วิธีนี้หลีกเลี่ยงการทำชื่อรายงานซ้ำใน attribute
อย่าใส่ label ให้ทุกอย่าง
ไม่ใช่ทุก element ที่ต้องมี ARIA label
ข้อความแบบ static โดยทั่วไปไม่ต้องมี ไอคอนตกแต่งไม่ต้องมี container ก็ไม่ต้องมี เว้นแต่จะมี landmark หรือ widget role ที่มีความหมาย การใส่ label มากเกินไปอาจทำให้หน้ามีเสียงรบกวนและนำทางยากขึ้น
สำหรับรูปภาพ ให้ใช้โมเดลเฉพาะของรูปภาพ: รูปภาพที่มีความหมายต้องมี alt ที่มีประโยชน์; รูปภาพตกแต่งต้องมี alt="" ว่าง อย่าใช้ ARIA labels แทนข้อความรูปภาพที่ดี หากทีมของคุณกำลังปะปนแนวคิดเหล่านี้ ให้กลับไปอ่าน alt text สำหรับรูปภาพแบบปฏิบัติได้จริง และแยก alternative ของรูปภาพออกจากชื่อของ control
ข้อผิดพลาดที่พบบ่อยคือการใส่ aria-label ให้ SVG ทุกตัว หาก SVG อยู่ภายในปุ่มและปุ่มมีชื่ออยู่แล้ว โดยทั่วไปควรซ่อนไอคอนจาก assistive tech:
<button aria-label="Open menu">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
มิฉะนั้นผู้ใช้อาจได้ยินการประกาศที่ซ้ำซ้อนหรือแปลกไป ขึ้นอยู่กับการผสมกันของ browser และ assistive technology
ตรวจสอบ computed name ไม่ใช่แค่ code
accessibility bugs มักรอดจาก code review เพราะ markup ดูน่าเชื่อถือ
เครื่องมือสำหรับนักพัฒนาใน browser สมัยใหม่สามารถแสดง computed accessibility tree ได้ ใน Chrome, Edge, Firefox และ Safari ให้ inspect element แล้วมองหาข้อมูล accessibility เช่น role, name และ description คุณกำลังตรวจสามเรื่อง:
- role เป็นอย่างที่คุณคาดหวังหรือไม่?
- accessible name ชัดเจนและเฉพาะเจาะจงหรือไม่?
- description มีประโยชน์โดยไม่แทนที่ name หรือไม่?
จากนั้นทดสอบ flow บางส่วนด้วย screen reader จริง คุณไม่จำเป็นต้องกลายเป็นผู้เชี่ยวชาญ assistive technology แบบเต็มเวลาเพื่อจับประเด็นพื้นฐาน บน macOS มี VoiceOver มาในตัว บน Windows, NVDA ใช้กันแพร่หลายและฟรี บน mobile ให้ทดสอบด้วย VoiceOver บน iOS และ TalkBack บน Android เมื่อเกี่ยวข้อง
เครื่องมืออัตโนมัติมีประโยชน์ แต่ไม่สามารถบอกได้อย่างน่าเชื่อถือว่า “Open,” “Read more,” หรือ “Delete” มีบริบทเพียงพอหรือไม่ ให้มอง automation เป็นตาข่าย ไม่ใช่ผู้ตัดสิน คล้ายกับการ audit performance: report สามารถชี้ไปยังพื้นที่ที่น่าสงสัยได้ แต่คุณยังต้องตีความผลกระทบเอง แนวทางที่สุขุมแบบเดียวกับที่เราแนะนำสำหรับ การอ่าน Lighthouse report โดยไม่ตื่นตระหนก ใช้กับเรื่องนี้ได้เช่นกัน
checklist สำหรับ review ที่ใช้ได้จริง
ก่อนปล่อย ARIA labels ให้ถามว่า:
- สิ่งนี้ใช้ native HTML แทนได้หรือไม่?
- มีข้อความที่มองเห็นได้ซึ่งควรใช้เป็น label หรือไม่?
- ถ้ามีข้อความที่มองเห็นได้ accessible name รวมข้อความนั้นไว้หรือไม่?
- control ที่ซ้ำกันมีเอกลักษณ์เมื่อถูกนำทางนอกบริบทที่มองเห็นได้หรือไม่?
- help text ถูกเชื่อมด้วย
aria-describedbyไม่ใช่ถูกยัดเข้าไปใน label หรือไม่? - ไอคอนตกแต่งถูกซ่อนจาก assistive technology หรือไม่?
- มีใครตรวจ computed accessibility name ใน browser dev tools แล้วหรือยัง?
- มีการทดสอบ critical flow ด้วย screen reader จริงอย่างน้อยหนึ่งรอบแล้วหรือยัง?
checklist นี้จับปัญหา label ส่วนใหญ่ได้ก่อนที่มันจะกลายเป็นปัญหาของผู้ใช้
วินัยเงียบ ๆ ของ ARIA ที่ดี
งาน ARIA ที่ดีแทบไม่เคยหวือหวา ส่วนใหญ่คือความยับยั้งชั่งใจ
ใช้ปุ่มจริง ใช้ label จริง ทำให้ชื่อที่มองเห็นได้และชื่อที่เข้าถึงได้สอดคล้องกัน เพิ่ม aria-label เฉพาะเมื่อไม่มีแหล่งที่มาที่มองเห็นได้ที่ดีกว่า ใช้ aria-labelledby เมื่อหน้ามีข้อความที่ถูกต้องอยู่แล้ว ใช้ aria-describedby สำหรับคำแนะนำสนับสนุนและ error
web platform ให้หลายสิ่งกับนักพัฒนาฟรีเมื่อเราใช้มันโดยตรง ARIA มีไว้สำหรับช่องว่าง ทักษะคือการรู้ว่าเมื่อใดมีช่องว่างจริง ๆ