บทแนะนำนี้จะอธิบายวิธีสร้างการนําทางหลักที่เข้าถึงได้ของเว็บไซต์ คุณจะได้เรียนรู้เกี่ยวกับ HTML เชิงความหมาย การช่วยเหลือพิเศษ และวิธีที่การใช้แอตทริบิวต์ ARIA อาจส่งผลเสียมากกว่าผลดีในบางครั้ง
การสร้างการนําทางหลักของเว็บไซต์มีหลายวิธี ทั้งในแง่ของการจัดสไตล์ ฟังก์ชันการทำงาน มาร์กอัป และข้อมูลเชิงความหมายพื้นฐาน หากการใช้งานมีน้อยเกินไป ผู้ใช้ส่วนใหญ่อาจใช้งานได้ แต่ประสบการณ์ของผู้ใช้ (UX) อาจไม่ดี หากมีการออกแบบที่ซับซ้อนเกินไป ก็อาจทำให้ผู้ใช้สับสนหรือเข้าถึงไม่ได้เลย
สําหรับเว็บไซต์ส่วนใหญ่ คุณควรสร้างเว็บไซต์ที่ทั้งไม่ง่ายและไม่ซับซ้อนจนเกินไป
การสร้างทีละเลเยอร์
ในบทแนะนำนี้ คุณจะเริ่มด้วยการตั้งค่าพื้นฐานและเพิ่มฟีเจอร์ทีละชั้นจนกว่าจะถึงจุดที่คุณให้ข้อมูล การจัดสไตล์ และฟังก์ชันการทำงานเพียงพอที่จะทำให้ผู้ใช้ส่วนใหญ่พึงพอใจ คุณต้องใช้หลักการการปรับปรุงแบบเป็นขั้นเป็นตอน ซึ่งระบุว่าให้เริ่มต้นด้วยโซลูชันพื้นฐานและมีประสิทธิภาพมากที่สุด แล้วค่อยๆ เพิ่มฟังก์ชันการทำงานทีละชั้น หากเลเยอร์หนึ่งไม่ทํางานด้วยเหตุผลบางประการ การนำทางจะยังคงทํางานต่อไปเนื่องจากระบบจะเปลี่ยนกลับไปใช้เลเยอร์ที่อยู่เบื้องล่าง
โครงสร้างพื้นฐาน
สำหรับการนําทางพื้นฐาน คุณต้องมี 2 อย่าง ได้แก่ องค์ประกอบ <a>
และ CSS 2-3 บรรทัดเพื่อปรับปรุงสไตล์และเลย์เอาต์เริ่มต้นของลิงก์
<a href="/home">Home</a>
<a href="/about-us">About us</a>
<a href="/pricing">Pricing</a>
<a href="/contact">Contact</a>
/* Define variables for your colors */
:root {
--color-shades-dark: rgb(25, 25, 25);
}
/* Use the alternative box model
Details: <https://web.dev/learn/css/box-model/> */
*{
box-sizing: border-box;
}
/* Basic font styling */
body {
font-family: Segoe UI, system-ui, -apple-system, sans-serif;
font-size: 1.6rem;
}
/* Link styling */
a {
--text-color: var(--color-shades-dark);
border-block-end: 3px solid var(--border-color, transparent);
color: var(--text-color);
display: inline-block;
margin-block-end: 0.5rem; /* See note at the bottom of this chapter */
margin-inline-end: 0.5rem;
padding: 0.1rem;
text-decoration: none;
}
/* Change the border-color on :hover and :focus */
a:where(:hover, :focus) {
--border-color: var(--text-color);
}
วิธีนี้ได้ผลดีกับผู้ใช้ส่วนใหญ่ ไม่ว่าจะเข้าถึงเว็บไซต์ด้วยวิธีใดก็ตาม คุณสามารถไปยังส่วนต่างๆ โดยใช้เมาส์ แป้นพิมพ์ อุปกรณ์สัมผัส หรือโปรแกรมอ่านหน้าจอได้ แต่ยังมีจุดที่ต้องปรับปรุง คุณสามารถปรับปรุงประสบการณ์การใช้งานได้โดยขยายรูปแบบพื้นฐานนี้ด้วยฟังก์ชันการทำงานและข้อมูลเพิ่มเติม
คุณสามารถดำเนินการได้ดังนี้
- ไฮไลต์หน้าเว็บที่ใช้งานอยู่
- ประกาศจำนวนรายการให้ผู้ใช้โปรแกรมอ่านหน้าจอทราบ
- เพิ่มจุดสังเกตและอนุญาตให้ผู้ใช้โปรแกรมอ่านหน้าจอเข้าถึงการไปยังส่วนต่างๆ ได้โดยตรงโดยใช้แป้นพิมพ์ลัด
- ซ่อนการนําทางในวิวพอร์ตแคบ
- ปรับปรุงการจัดรูปแบบโฟกัส
ไฮไลต์หน้าเว็บที่ใช้งานอยู่
หากต้องการไฮไลต์หน้าเว็บที่ใช้งานอยู่ ให้เพิ่มคลาสลงในลิงก์ที่เกี่ยวข้อง
<a href="/about-us" class="active-page">About us</a>
ปัญหาของแนวทางนี้คือการแสดงข้อมูลว่าลิงก์ใดทำงานอยู่นั้นใช้ภาพอย่างเดียว ผู้ใช้โปรแกรมอ่านหน้าจอที่เป็นใบ้ไม่สามารถแยกความแตกต่างระหว่างหน้าเว็บที่ใช้งานอยู่และหน้าอื่นๆ แต่มาตรฐาน Accessible Rich Internet Applications (ARIA) มีวิธีสื่อสารข้อมูลนี้ตามความหมายด้วย ใช้แอตทริบิวต์และค่า aria-current="page" แทนคลาส
aria-current
(สถานะ) ระบุองค์ประกอบที่แสดงถึงรายการปัจจุบันภายในคอนเทนเนอร์หรือชุดองค์ประกอบที่เกี่ยวข้อง
โทเค็นหน้าเว็บที่ใช้ระบุลิงก์ภายในชุดลิงก์การแบ่งหน้า ซึ่งลิงก์จะมีการจัดรูปแบบที่มองเห็นได้เพื่อแสดงหน้าเว็บที่แสดงอยู่ในปัจจุบัน
[แอปพลิเคชัน Rich Internet ที่เข้าถึงได้ (WAI-ARIA) 1.1](https://www.w3.org/TR/wai-aria/#aria-current)
เมื่อใช้แอตทริบิวต์เพิ่มเติม โปรแกรมอ่านหน้าจอจะอ่านออกเสียงเป็น "หน้าปัจจุบัน ลิงก์ เกี่ยวกับเรา" แทนที่จะอ่านแค่ "ลิงก์ เกี่ยวกับเรา"
<a href="/about-us" aria-current="page" class="active-page">About us</a>
ข้อดีอีกอย่างหนึ่งคือ คุณสามารถใช้แอตทริบิวต์นี้เพื่อเลือกลิงก์ที่ใช้งานอยู่ใน CSS ซึ่งทำให้คลาส active-page
ล้าสมัย
<a href="/home">Home</a>
<a href="/about-us" aria-current="page">About us</a>
<a href="/pricing">Pricing</a>
<a href="/contact">Contact</a>
/* Change border-color and color for the active page */
[aria-current="page"] {
--border-color: var(--color-highlight);
--text-color: var(--color-highlight);
}
ประกาศจำนวนรายการ
เมื่อดูที่การนําทาง ผู้ใช้ที่มองเห็นจะทราบว่ามีเพียง 4 ลิงก์เท่านั้น ผู้ใช้โปรแกรมอ่านหน้าจอที่ตาบอดจะรับข้อมูลนี้ไม่ได้เร็วนัก ผู้ชมอาจต้องดูลิงก์ทั้งหมด การดำเนินการนี้อาจไม่มีปัญหาหากรายการมีความยาวไม่มากนัก เช่น ในตัวอย่างนี้ แต่หากมีลิงก์ 40 รายการ การดำเนินการนี้อาจยุ่งยาก หากผู้ใช้โปรแกรมอ่านหน้าจอทราบตั้งแต่ต้นว่าการนำทางมีลิงก์จำนวนมาก ผู้ใช้อาจเลือกใช้วิธีอื่นในการไปยังส่วนต่างๆ ที่มีประสิทธิภาพมากกว่า เช่น การค้นหาเว็บไซต์
วิธีที่ดีในการสื่อสารจำนวนรายการล่วงหน้าคือการตัดลิงก์แต่ละรายการในรายการ (<li>
) ที่ฝังอยู่ในรายการที่ไม่มีลําดับ (<ul>
)
<ul>
<li>
<a href="/home">Home</a>
</li>
<li>
<a href="/about-us" aria-current="page">About us</a>
</li>
<li>
<a href="/pricing">Pricing</a>
</li>
<li>
<a href="/contact">Contact</a>
</li>
</ul>
เมื่อผู้ใช้โปรแกรมอ่านหน้าจอพบรายการ ซอฟต์แวร์จะประกาศว่า "รายการ 4 รายการ"
ต่อไปนี้เป็นตัวอย่างการไปยังส่วนต่างๆ ที่ใช้กับโปรแกรมอ่านหน้าจอ NVDA ใน Windows
ตอนนี้คุณต้องปรับสไตล์เพื่อให้ดูเหมือนก่อน
/* Remove the default list styling and create a flexible layout for the list */
ul {
display: flex;
flex-wrap: wrap;
gap: 1rem;
list-style: none;
margin: 0;
padding: 0;
}
/* Basic link styling */
a {
--text-color: var(--color-shades-dark);
border-block-end: 3px solid var(--border-color, transparent);
color: var(--text-color);
padding: 0.1rem;
text-decoration: none;
}
การใช้ลิสต์มีข้อดีหลายประการสำหรับผู้ใช้โปรแกรมอ่านหน้าจอ ดังนี้
- ผู้ใช้จะเห็นจำนวนรายการทั้งหมดก่อนที่จะโต้ตอบกับรายการ
- ผู้ชมอาจใช้แป้นพิมพ์ลัดเพื่อข้ามจากรายการหนึ่งไปยังรายการถัดไป
- โดยอาจใช้แป้นพิมพ์ลัดเพื่อข้ามจากรายการหนึ่งไปยังอีกรายการหนึ่ง
- โปรแกรมอ่านหน้าจออาจอ่านออกเสียงดัชนีของรายการปัจจุบัน (เช่น "รายการที่ 2 จาก 4")
นอกจากนี้ หากหน้าเว็บแสดงโดยไม่มี CSS รายการจะแสดงลิงก์เป็นกลุ่มรายการที่สอดคล้องกันแทนที่จะเป็นกองลิงก์
รายละเอียดที่น่าสนใจเกี่ยวกับ VoiceOver ใน Safari คือคุณจะเสียสิทธิประโยชน์ทั้งหมดเหล่านี้เมื่อตั้งค่า list-style: none
การดำเนินการนี้เป็นไปตามการออกแบบ ทีม WebKit จึงตัดสินใจที่จะนำความหมายของรายการออกเมื่อรายการนั้นดูไม่เหมือนรายการ การดำเนินการนี้อาจทำให้เกิดปัญหาหรือไม่ก็ได้ ทั้งนี้ขึ้นอยู่กับความซับซ้อนของการนําทาง ในทางกลับกัน การนำทางยังคงใช้งานได้และจะส่งผลต่อ VoiceOver ใน Safari เท่านั้น VoiceOver ที่ใช้กับ Chrome หรือ Firefox จะยังคงอ่านออกเสียงจำนวนรายการ รวมถึงโปรแกรมอ่านหน้าจออื่นๆ เช่น NVDA ในทางกลับกัน ข้อมูลเชิงความหมายอาจมีประโยชน์มากในบางสถานการณ์ หากต้องการตัดสินใจ คุณควรทดสอบการไปยังส่วนต่างๆ กับผู้ใช้โปรแกรมอ่านหน้าจอจริงและรับความคิดเห็นจากผู้ใช้ หากต้องการใช้ VoiceOver ใน Safari ให้ทำงานเหมือนโปรแกรมอ่านหน้าจออื่นๆ ทั้งหมด คุณสามารถแก้ปัญหานี้ได้โดยการตั้งค่าบทบาทรายการ ARIA อย่างชัดเจนใน <ul>
ซึ่งจะเปลี่ยนลักษณะการทำงานกลับเป็นสถานะก่อนที่คุณจะนำการจัดรูปแบบรายการออก รายการจะยังคงมีลักษณะเหมือนเดิม
<ul role="list">
<li>
<a href="/home">Home</a>
</li>
...
</ul>
เพิ่มจุดสังเกต
คุณทําการปรับปรุงที่ดีเยี่ยมสําหรับผู้ใช้โปรแกรมอ่านหน้าจอได้ง่ายๆ แต่ยังมีอีก 1 อย่างที่คุณทําได้ การนำทางยังคงเป็นเพียงรายการลิงก์ตามความหมาย และยากที่จะบอกได้ว่ารายการที่เฉพาะเจาะจงนี้เป็นการนำทางหลักของเว็บไซต์ คุณสามารถเปลี่ยนรายการธรรมดานี้ให้เป็นรายการการนำทางได้โดยการตัด <ul>
ไว้ในองค์ประกอบ <nav>
การใช้องค์ประกอบ <nav>
มีข้อดีหลายประการ สิ่งที่น่าสังเกตคือโปรแกรมอ่านหน้าจอจะประกาศว่า "การไปยังส่วนต่างๆ" เมื่อผู้ใช้โต้ตอบกับโปรแกรมอ่านหน้าจอ และเพิ่มจุดสังเกตลงในหน้า จุดสังเกตคือบริเวณพิเศษในหน้า เช่น <header>
, <footer>
หรือ <main>
ซึ่งโปรแกรมอ่านหน้าจอสามารถข้ามไป จุดสังเกตในหน้าเว็บมีประโยชน์เนื่องจากช่วยให้ผู้ใช้โปรแกรมอ่านหน้าจอเข้าถึงส่วนสําคัญในหน้าเว็บได้โดยตรงโดยไม่ต้องโต้ตอบกับส่วนอื่นๆ ของหน้า เช่น คุณสามารถข้ามจากจุดสังเกตหนึ่งไปยังอีกจุดหนึ่งได้โดยกดแป้น D ใน NVDA ใน VoiceOver คุณสามารถใช้โรเตอร์เพื่อแสดงจุดสังเกตทั้งหมดในหน้าเว็บได้โดยกด VO + U

ในรายการนี้คุณจะเห็นจุดสังเกต 4 จุด ได้แก่ แบนเนอร์ ซึ่งเป็นองค์ประกอบ <header>
, การนําทางคือองค์ประกอบ <nav>
, หลักคือองค์ประกอบ <main>
และข้อมูลเนื้อหาคือองค์ประกอบ <footer>
รายการนี้ไม่ควรยาวเกินไป คุณควรทำเครื่องหมายเฉพาะส่วนสำคัญของ UI เท่านั้น เช่น การค้นหาเว็บไซต์ การนำทางในพื้นที่ หรือการแบ่งหน้า
หากคุณมีการนำทางทั่วทั้งเว็บไซต์ การนำทางภายในหน้าเว็บ และการจัดแบ่งหน้าในหน้าเดียว คุณอาจมีองค์ประกอบ <nav>
3 รายการด้วย ไม่เป็นไร แต่ตอนนี้มีจุดสังเกตในการนําทาง 3 จุดและทั้งหมดมีลักษณะเหมือนกันในแง่ความหมาย ซึ่งแยกแยะได้ลำบากจริงๆ เว้นแต่คุณจะรู้โครงสร้างของหน้าเว็บเป็นอย่างดี

คุณควรติดป้ายกำกับโดยใช้ aria-labelledby
หรือ aria-label
เพื่อให้แยกความแตกต่างได้
<nav aria-label="Main">
<ul>
<li>
<a href="/home">Home</a>
</li>
...
</ul>
</nav>
...
<nav aria-label="Select page">
<ul>
<li>
<a href="/page-1">1</a>
</li>
...
</ul>
</nav>
หากป้ายกำกับที่คุณเลือกมีอยู่แล้วในหน้าเว็บ ให้ใช้ aria-labelledby
แทนและอ้างอิงป้ายกำกับที่มีอยู่โดยใช้แอตทริบิวต์ id
<nav aria-labelledby="pagination_heading">
<h2 id="pagination_heading">Select a page</h2>
<ul>
<li>
<a href="/page-1">1</a>
</li>
...
</ul>
</nav>
ป้ายกำกับที่กระชับก็เพียงพอแล้ว อย่าเขียนให้ยาวเกินไป หลีกเลี่ยงการใช้คําอย่างเช่น "การนําทาง" หรือ "เมนู" เนื่องจากโปรแกรมอ่านหน้าจอให้ข้อมูลนี้แก่ผู้ใช้อยู่แล้ว

ซ่อนการนําทางในวิวพอร์ตแคบ
โดยส่วนตัวแล้ว เราไม่ค่อยชอบการซ่อนการนําทางหลักในวิวพอร์ตแคบ แต่หากรายการลิงก์ยาวเกินไป ก็คงไม่มีทางเลือกอื่น ในกรณีนี้ ผู้ใช้จะเห็นปุ่ม "เมนู" หรือไอคอนแฮมเบอร์เกอร์ หรือทั้ง 2 อย่างรวมกันแทนรายการ การคลิกปุ่มจะแสดงและซ่อนรายการ หากรู้จัก JavaScript และ CSS พื้นฐาน คุณจะทําได้ แต่ต้องคำนึงถึง UX และการช่วยเหลือพิเศษหลายอย่าง
- คุณต้องซ่อนรายการในลักษณะที่เข้าถึงได้
- การนำทางต้องเข้าถึงได้ด้วยแป้นพิมพ์
- การนำทางต้องสื่อสารว่าผู้ใช้มองเห็นหรือไม่
การเพิ่มปุ่มเมนูแบบสามเหลี่ยม
เนื่องจากคุณใช้หลักการการปรับปรุงแบบเป็นขั้นเป็นตอน คุณจึงต้องตรวจสอบว่าการไปยังส่วนต่างๆ ยังคงใช้งานได้และสมเหตุสมผลแม้ว่าจะปิด JavaScript อยู่ก็ตาม
สิ่งแรกที่การไปยังส่วนต่างๆ ต้องมีคือปุ่มสามเหลี่ยมแนวนอน คุณสร้างเมนูใน HTML ในองค์ประกอบเทมเพลต โคลนเมนูใน JavaScript และเพิ่มลงในการนำทาง

<nav id="mainnav">
...
</nav>
<template id="burger-template">
<button type="button" aria-expanded="false" aria-label="Menu" aria-controls="mainnav">
<svg width="24" height="24" aria-hidden="true">
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z">
</svg>
</button>
</template>
- แอตทริบิวต์
aria-expanded
จะบอกซอฟต์แวร์โปรแกรมอ่านหน้าจอว่าองค์ประกอบที่ปุ่มควบคุมนั้นขยายอยู่หรือไม่ aria-label
ตั้งชื่อที่เรียกกันว่าชื่อสำหรับการช่วยเหลือพิเศษให้กับปุ่ม ซึ่งเป็นข้อความแสดงแทนสำหรับไอคอนสามเหลี่ยมซ้อนกัน- คุณซ่อน
<svg>
จากเทคโนโลยีความช่วยเหลือพิเศษโดยใช้aria-hidden
เนื่องจากมีป้ายกำกับข้อความที่aria-label
ระบุไว้อยู่แล้ว aria-controls
บอกเทคโนโลยีความช่วยเหลือพิเศษที่รองรับแอตทริบิวต์ (เช่น JAWS) ว่าปุ่มควบคุมองค์ประกอบใด
const nav = document.querySelector('#mainnav')
const list = nav.querySelector('ul');
const burgerClone = document.querySelector('#burger-template').content.cloneNode(true);
const button = burgerClone.querySelector('button');
// Toggle aria-expanded attribute
button.addEventListener('click', e => {
// aria-expanded="true" signals that the menu is currently open
const isOpen = button.getAttribute('aria-expanded') === "true"
button.setAttribute('aria-expanded', !isOpen);
});
// Hide list on keydown Escape
nav.addEventListener('keyup', e => {
if (e.code === 'Escape') {
button.setAttribute('aria-expanded', false);
}
});
// Add the button to the page
nav.insertBefore(burgerClone, list);
- ผู้ใช้สามารถปิดการนําทางได้ทุกเมื่อที่ต้องการ เช่น โดยการกดแป้น Escape
- คุณควรใช้
insertBefore
แทนappendChild
เนื่องจากปุ่มควรเป็นองค์ประกอบแรกในการนําทาง หากผู้ใช้แป้นพิมพ์หรือโปรแกรมอ่านหน้าจอกด Tab หลังจากคลิกปุ่ม ผู้ใช้จะคาดหวังว่าระบบจะโฟกัสที่รายการแรกในรายการ แต่หากปุ่มอยู่หลังรายการ ปัญหานี้จะไม่เกิดขึ้น
จากนั้นให้รีเซ็ตการจัดรูปแบบเริ่มต้นของปุ่มและตรวจสอบว่าปุ่มดังกล่าวจะแสดงเฉพาะในวิวพอร์ตแคบเท่านั้น
@media (min-width: 48em) {
nav {
--nav-button-display: none;
}
}
/* Reset button styling */
button {
all: unset;
display: var(--nav-button-display, flex);
}
การซ่อนรายการ
ก่อนซ่อนรายการ ให้จัดตำแหน่งและกำหนดสไตล์การนําทางและรายการเพื่อให้เลย์เอาต์ได้รับการเพิ่มประสิทธิภาพสําหรับวิวพอร์ตแคบๆ แต่ยังคงดูดีบนหน้าจอขนาดใหญ่
ขั้นแรก ให้นำ <nav>
ออกจากลำดับปกติของหน้าเว็บและวางไว้ที่มุมบนสุดของวิวพอร์ต
@media (min-width: 48em) {
nav {
--nav-button-display: none;
--nav-position: static;
}
}
nav {
position: var(--nav-position, fixed);
inset-block-start: 1rem;
inset-inline-end: 1rem;
}
ถัดไป ให้เปลี่ยนเลย์เอาต์ในวิวพอร์ตแคบโดยเพิ่มพร็อพเพอร์ตี้ที่กำหนดเองใหม่ (—-nav-list-layout)
เลย์เอาต์จะเป็นคอลัมน์โดยค่าเริ่มต้นและเปลี่ยนเป็นแถวในหน้าจอขนาดใหญ่
@media (min-width: 48em) {
nav {
--nav-button-display: none;
--nav-position: static;
}
ul {
--nav-list-layout: row;
}
}
ul {
display: flex;
flex-direction: var(--nav-list-layout, column);
flex-wrap: wrap;
gap: 1rem;
list-style: none;
margin: 0;
padding: 0;
}
การนำทางควรมีลักษณะดังต่อไปนี้ในวิวพอร์ตแคบ

รายการนี้ต้องใช้ CSS อย่างแน่นอน เราจะย้ายรูปภาพขึ้นไปที่มุมบนสุด ปรับให้เต็มหน้าจอในแนวตั้ง ใส่ background-color
และ box-shadow
@media (min-width: 48em) {
nav {
--nav-button-display: none;
--nav-position: static;
}
ul {
--nav-list-layout: row;
--nav-list-position: static;
--nav-list-padding: 0;
--nav-list-height: auto;
--nav-list-width: 100%;
--nav-list-shadow: none;
}
}
ul {
background: rgb(255, 255, 255);
box-shadow: var(--nav-list-shadow, -5px 0 11px 0 rgb(0 0 0 / 0.2));
display: flex;
flex-direction: var(--nav-list-layout, column);
flex-wrap: wrap;
gap: 1rem;
height: var(--nav-list-height, 100vh);
list-style: none;
margin: 0;
padding: var(--nav-list-padding, 2rem);
position: var(--nav-list-position, fixed);
inset-block-start: 0; /* Logical property. Equivalent to top: 0; */
inset-inline-end: 0; /* Logical property. Equivalent to right: 0; */
width: var(--nav-list-width, min(22rem, 100vw));
}
button {
all: unset;
display: var(--nav-button-display, flex);
position: relative;
z-index: 1;
}
รายการควรมีลักษณะดังตัวอย่างนี้ในวิวพอร์ตแคบๆ ซึ่งมีลักษณะคล้ายกับแถบด้านข้างมากกว่ารายการธรรมดา

สุดท้าย ให้ซ่อนรายการ แสดงเฉพาะเมื่อผู้ใช้คลิกปุ่ม 1 ครั้ง และซ่อนเมื่อผู้ใช้คลิกอีกครั้ง สิ่งสำคัญคือให้ซ่อนเฉพาะรายการ ไม่ใช่การนําทางทั้งหมด เนื่องจากการซ่อนการนําทางจะเป็นการซ่อนจุดสังเกตที่สําคัญด้วย
ก่อนหน้านี้คุณได้เพิ่มเหตุการณ์คลิกลงในปุ่มเพื่อสลับค่าของแอตทริบิวต์ aria-expanded
คุณสามารถใช้ข้อมูลดังกล่าวเป็นเงื่อนไขในการแสดงและซ่อนรายการใน CSS ได้
@media (min-width: 48em) {
ul {
--nav-list-visibility: visible;
}
}
ul {
visibility: var(--nav-list-visibility, visible);
}
/* Hide the list on narrow viewports, if it comes after an element with
aria-expanded set to "false". */
[aria-expanded="false"] + ul {
visibility: var(--nav-list-visibility, hidden);
}
คุณควรใช้การประกาศพร็อพเพอร์ตี้ เช่น visibility: hidden
หรือ display: none
แทน opacity: 0
หรือ translateX(100%)
เพื่อซ่อนรายการ พร็อพเพอร์ตี้เหล่านี้ช่วยให้มั่นใจว่าผู้ใช้จะโฟกัสลิงก์ไม่ได้เมื่อซ่อนการนําทาง การใช้ opacity
หรือ translate
จะนําเนื้อหาออกเพื่อให้ผู้ใช้ไม่เห็นลิงก์ แต่ยังคงเข้าถึงได้โดยใช้แป้นพิมพ์ ซึ่งอาจทําให้ผู้ใช้สับสนและหงุดหงิด การใช้ visibility
หรือ display
จะซ่อนรายการนั้นๆ ไม่ให้ผู้ใช้เห็นและเข้าถึงไม่ได้ จึงเป็นการซ่อนรายการนั้นๆ สำหรับผู้ใช้ทุกคน
การทำรายการเคลื่อนไหว
หากสงสัยว่าทำไมจึงควรใช้ visibility: hidden;
แทน display: none;
นั่นเป็นเพราะคุณสามารถทำให้ระดับการมองเห็นเคลื่อนไหวได้ พร็อพเพอร์ตี้นี้มีสถานะเพียง 2 สถานะ ได้แก่ hidden
และ visible
แต่คุณสามารถรวมกับพร็อพเพอร์ตี้อื่น เช่น transform
หรือ opacity
เพื่อสร้างเอฟเฟกต์การเลื่อนหรือค่อยๆ ปรากฏ การดำเนินการดังกล่าวจะใช้กับ display: none ไม่ได้เนื่องจากพร็อพเพอร์ตี้ display เป็นแบบคงที่
การเปลี่ยน CSS ต่อไปนี้ opacity
เพื่อสร้างเอฟเฟกต์การค่อยๆ ปรากฏขึ้นและค่อยๆ หายไป
ul {
transition: opacity 0.6s linear, visibility 0.3s linear;
visibility: var(--nav-list-visibility, visible);
}
[aria-expanded="false"] + ul {
opacity: 0;
visibility: var(--nav-list-visibility, hidden);
}
หากต้องการแสดงภาพเคลื่อนไหวแทน คุณควรพิจารณาตัดแต่งพร็อพเพอร์ตี้ transition
ในคําค้นหาสื่อ prefers-reduced-motion เนื่องจากภาพเคลื่อนไหวอาจทริกเกอร์อาการคลื่นไส้ วิงเวียนศีรษะ และปวดหัวในผู้ใช้บางราย
ul {
visibility: var(--nav-list-visibility, visible);
}
@media (prefers-reduced-motion: no-preference) {
ul {
transition: transform 0.6s cubic-bezier(.68,-0.55,.27,1.55), visibility 0.3s linear;
}
}
[aria-expanded="false"] + ul {
transform: var(--nav-list-transform, translateX(100%));
visibility: var(--nav-list-visibility, hidden);
}
วิธีนี้ช่วยให้มั่นใจได้ว่าจะมีเพียงผู้ที่ไม่ได้ตั้งค่าให้ลดการเคลื่อนไหวเท่านั้นที่เห็นภาพเคลื่อนไหว
ปรับปรุงการจัดรูปแบบโฟกัส
ผู้ใช้แป้นพิมพ์ต้องอาศัยรูปแบบโฟกัสขององค์ประกอบเพื่อหาทิศทางและไปยังส่วนต่างๆ ในหน้า สไตล์โฟกัสเริ่มต้นดีกว่าไม่มีสไตล์โฟกัส (ซึ่งจะเกิดขึ้นหากคุณตั้งค่า outline: none
) แต่การมีสไตล์โฟกัสที่กำหนดเองที่มองเห็นได้ชัดเจนยิ่งขึ้นจะช่วยปรับปรุงประสบการณ์ของผู้ใช้
ลักษณะโฟกัสเริ่มต้นของลิงก์ใน Chrome 103 มีดังนี้

คุณสามารถปรับปรุงได้โดยระบุสไตล์ของคุณเองในสีที่คุณชอบ การใช้ :focus-visible
แทน :focus
เป็นการปล่อยให้เบราว์เซอร์ตัดสินใจว่าควรแสดงสไตล์โฟกัสเมื่อใด สไตล์ :focus
จะแสดงให้ผู้ใช้ทุกคนเห็น ไม่ว่าจะเป็นผู้ใช้เมาส์ แป้นพิมพ์ หรือระบบสัมผัส ไม่ว่าผู้ใช้เหล่านั้นจะต้องการหรือไม่ก็ตาม เมื่อใช้ :focus-visible
เบราว์เซอร์จะใช้วิธีการหาค่าประมาณภายในเพื่อตัดสินใจว่าจะแสดงเฉพาะแก่ผู้ใช้แป้นพิมพ์หรือแก่ทุกคน
/* Remove the default :focus outline */
*:focus {
outline: none;
}
/* Show a custom outline on :focus-visible */
*:focus-visible {
outline: 2px solid var(--color-shades-dark);
outline-offset: 4px;
}
การรองรับเบราว์เซอร์สำหรับ :focus-visible

การไฮไลต์รายการเมื่อโฟกัสมีด้วยกันหลายวิธี เราขอแนะนำให้ใช้พร็อพเพอร์ตี้ outline
เนื่องจากจะไม่ทำให้เลย์เอาต์แตก ซึ่งอาจเกิดขึ้นได้กับ border
และทำงานร่วมกับโหมดคอนทราสต์สูงใน Windows ได้เป็นอย่างดี พร็อพเพอร์ตี้ที่ทำงานได้ไม่ดีคือ background-color
หรือ box-shadow
เนื่องจากอาจไม่แสดงเลยเมื่อใช้การตั้งค่าคอนทราสต์ที่กำหนดเอง

ยินดีด้วย คุณได้สร้างการนําทางหลักที่ปรับปรุงอย่างต่อเนื่อง สื่อความหมายชัดเจน เข้าถึงได้ และเหมาะกับอุปกรณ์เคลื่อนที่
ทุกอย่างสามารถปรับปรุงได้เสมอ เช่น
- คุณอาจพิจารณาตรึงโฟกัสไว้ในการนําทาง หรือทําให้ส่วนที่เหลือของหน้าไม่มีการเคลื่อนไหวในวิวพอร์ตแคบ
- คุณสามารถเพิ่มลิงก์ข้ามที่ด้านบนของหน้าเพื่อให้ผู้ใช้แป้นพิมพ์ข้ามการไปยังส่วนต่างๆ ได้
หากคุณยังจำจุดเริ่มต้นของบทความนี้ได้ นั่นคือจุดประสงค์ที่ว่า "วิธีแก้ปัญหาไม่ควรง่ายเกินไปหรือซับซ้อนเกินไป" ซึ่งตอนนี้เรามาถึงจุดนั้นแล้ว อย่างไรก็ตาม การนำทางอาจซับซ้อนเกินไป
การนำทางกับเมนู
การนำทางและเมนูมีความแตกต่างกันอย่างชัดเจน การนําทางคือคอลเล็กชันลิงก์สําหรับไปยังส่วนต่างๆ ของเอกสารที่เกี่ยวข้อง เมนูคือคอลเล็กชันการดำเนินการที่จะทำในเอกสาร บางครั้งงานเหล่านี้อาจทับซ้อนกัน คุณอาจมีการนำทางที่มีปุ่มที่ดำเนินการด้วย เช่น เปิดหน้าต่างโมดอล หรืออาจมีเมนูที่การดำเนินการหนึ่งนําไปยังหน้าอื่น เช่น หน้าความช่วยเหลือ ในกรณีนี้ คุณไม่ควรผสมบทบาท ARIA เข้าด้วยกัน แต่ให้ระบุวัตถุประสงค์หลักของคอมโพเนนต์ แล้วเลือกมาร์กอัปและบทบาทตามความเหมาะสม
องค์ประกอบ <nav>
มีบทบาท ARIA ที่ไม่ชัดแจ้งในการนําทาง ซึ่งเพียงพอที่จะสื่อสารว่าองค์ประกอบดังกล่าวเป็นการนําทาง แต่คุณมักจะเห็นเว็บไซต์ใช้เมนู แถบเมนู และเมนูรายการด้วย เนื่องจากบางครั้งเราใช้คําเหล่านี้แทนกันได้ เราจึงคิดว่าการรวมคําเหล่านี้เข้าด้วยกันเพื่อปรับปรุงประสบการณ์ของผู้ใช้โปรแกรมอ่านหน้าจอน่าจะเหมาะสม ก่อนที่จะดูว่าเหตุใดจึงไม่ใช่เช่นนั้น มาดูคำจำกัดความอย่างเป็นทางการของบทบาทเหล่านี้กัน
บทบาทการนําทาง
คอลเล็กชันองค์ประกอบในการไปยังส่วนต่างๆ (โดยปกติคือลิงก์) สำหรับไปยังส่วนต่างๆ ของเอกสารหรือเอกสารที่เกี่ยวข้อง
navigation (role) WAI-ARIA 1.1
บทบาทของเมนู
เมนูมักเป็นรายการการดำเนินการหรือฟังก์ชันทั่วไปที่ผู้ใช้เรียกใช้ได้ บทบาทของเมนูเหมาะสําหรับการแสดงรายการเมนูในลักษณะที่คล้ายกับเมนูในแอปพลิเคชันบนเดสก์ท็อป
menu (บทบาท) WAI-ARIA 1.1
บทบาทของแถบเมนู
การแสดงเมนูที่มักจะปรากฏอยู่เสมอและมักจะแสดงในแนวนอน บทบาทของแถบเมนูใช้ในการสร้างแถบเมนูที่คล้ายกับแถบเมนูในแอปพลิเคชันเดสก์ท็อปของ Windows, Mac และ Gnome แถบเมนูใช้เพื่อสร้างชุดคำสั่งที่ใช้บ่อยที่สอดคล้องกัน ผู้เขียนควรตรวจสอบว่าการโต้ตอบกับแถบเมนูคล้ายกับการโต้ตอบกับแถบเมนูทั่วไปในอินเทอร์เฟซผู้ใช้แบบกราฟิกของเดสก์ท็อป
menubar (role) WAI-ARIA 1.1
บทบาท menuitem
ตัวเลือกในชุดตัวเลือกที่มีเมนูหรือแถบเมนู
menuitem (role) WAI-ARIA 1.1
ข้อกำหนดนี้ชัดเจนมาก ให้ใช้การนําทางเพื่อไปยังส่วนต่างๆ ของเอกสารหรือเอกสารที่เกี่ยวข้อง และเมนูสําหรับรายการการดําเนินการหรือฟังก์ชันที่คล้ายกับเมนูในแอปพลิเคชันบนเดสก์ท็อปเท่านั้น หากไม่ได้สร้าง Google เอกสารเวอร์ชันถัดไป คุณอาจไม่จําเป็นต้องใช้บทบาทเมนูใดๆ ในการนําทางหลัก
การใช้เมนูจะเหมาะสมในกรณีใด
การใช้รายการเมนูหลักไม่ใช่เพื่อไปยังส่วนต่างๆ แต่เพื่อดำเนินการ สมมติว่าคุณมีรายการหรือตารางข้อมูลและผู้ใช้สามารถดําเนินการบางอย่างกับแต่ละรายการในรายการ คุณสามารถเพิ่มปุ่มในแต่ละแถวและแสดงการดำเนินการเมื่อผู้ใช้คลิกปุ่ม
<ul>
<li>
Product 1
<button aria-expanded="false" aria-controls="options1">Edit</button>
<div role="menu" id="options1">
<button role="menuitem">
Duplicate
</button>
<button role="menuitem">
Delete
</button>
<button role="menuitem">
Disable
</button>
</div>
</li>
<li>
Product 2
...
</li>
</ul>
ผลที่ตามมาของการใช้บทบาทเมนู
คุณต้องใช้บทบาทเมนูเหล่านี้อย่างชาญฉลาดเนื่องจากอาจเกิดข้อผิดพลาดได้มากมาย
เมนูต้องการโครงสร้าง DOM บางรายการ menuitem
ต้องเป็นรายการย่อยโดยตรงของ menu
โค้ดต่อไปนี้อาจทำให้ลักษณะการทำงานเชิงความหมายขัดข้อง
<!-- Wrong, don't do this -->
<ul role="menu">
<li>
<a href="#" role="menuitem">Item 1</a>
</li>
</ul>
ผู้ใช้ที่มีประสบการณ์คาดหวังว่าแป้นพิมพ์ลัดบางรายการจะใช้งานได้กับเมนูและแถบเมนู ข้อมูลดังกล่าวประกอบด้วยสิ่งต่อไปนี้ตามคู่มือแนวทางปฏิบัติด้านการเขียน ARIA (APG)
- Enter และ Space เพื่อเลือกรายการในเมนู
- ปุ่มลูกศรทุกทิศทางเพื่อไปยังรายการต่างๆ
- ปุ่ม Home และ End เพื่อย้ายโฟกัสไปยังรายการแรกหรือรายการสุดท้ายตามลำดับ
- a-z เพื่อย้ายโฟกัสไปยังรายการเมนูถัดไปที่มีป้ายกำกับที่ขึ้นต้นด้วยอักขระที่พิมพ์
- Esc เพื่อปิดเมนู
หากโปรแกรมอ่านหน้าจอตรวจพบเมนู ซอฟต์แวร์อาจเปลี่ยนโหมดการท่องเว็บโดยอัตโนมัติ ซึ่งจะช่วยให้ใช้แป้นพิมพ์ลัดที่กล่าวถึงก่อนหน้านี้ได้ ผู้ใช้โปรแกรมอ่านหน้าจอที่ไม่มีประสบการณ์อาจใช้เมนูไม่ได้เนื่องจากไม่รู้จักแป้นพิมพ์ลัดเหล่านี้หรือวิธีใช้
ผู้ใช้แป้นพิมพ์ที่อาจคาดหวังว่าจะใช้ Shift และ Shift + Tab ได้ก็จะใช้ไม่ได้เช่นกัน
การสร้างเมนูและแถบเมนูต้องพิจารณาหลายอย่าง โดยสิ่งแรกที่ต้องพิจารณาคือความเหมาะสมในการใช้เมนูและแถบเมนู เมื่อสร้างเว็บไซต์ทั่วไป คุณต้องใช้องค์ประกอบ nav ที่มีรายการและลิงก์เท่านั้น ซึ่งรวมถึงแอปพลิเคชันหน้าเว็บเดียว (SPA) หรือเว็บแอปด้วย สแต็กพื้นฐานไม่สำคัญ หลีกเลี่ยงการใช้บทบาทเมนู เว้นแต่คุณจะสร้างแอปพลิเคชันที่คล้ายกับแอปพลิเคชันบนเดสก์ท็อปมาก
แหล่งข้อมูลเพิ่มเติม
- Fixing Lists โดย Scott O'hara
- Don't Use ARIA Menu Roles for Site Nav โดย Adrian Roselli
- Menus & Menu Buttons โดย Heydon Pickering
- เมนู WAI-ARIA และเหตุผลที่คุณควรจัดการเมนูเหล่านี้อย่างระมัดระวัง โดย Marco Zehe
- การซ่อนเนื้อหาอย่างมีความรับผิดชอบ โดย Kitty Giraudel
- :focus-visible พร้อมใช้งานแล้ว โดย Matthias Ott
รูปภาพหลักโดย Mick Haupt