บทแนะนํานี้จะอธิบายวิธีสร้างการนําทางหลักของเว็บไซต์ที่เข้าถึงได้ คุณได้เรียนรู้เกี่ยวกับ 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
(สถานะ) ระบุองค์ประกอบที่แสดงรายการปัจจุบันในคอนเทนเนอร์หรือชุดขององค์ประกอบที่เกี่ยวข้อง
โทเค็นของหน้าเว็บที่ใช้เพื่อระบุลิงก์ภายในชุดของลิงก์ที่มีการแบ่งหน้า โดยที่ลิงก์จะมีรูปแบบเป็นรูปภาพเพื่อแสดงถึงหน้าเว็บที่แสดงอยู่ในปัจจุบัน
[Accessible Rich Internet Applications (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>
เพิ่มจุดสังเกต
คุณได้ทำการปรับปรุงที่ยอดเยี่ยมสำหรับผู้ใช้โปรแกรมอ่านหน้าจอโดยใช้ความพยายามเพียงเล็กน้อย แต่ยังมีอีกสิ่งหนึ่งที่ทำได้ การนำทางในเชิงอรรถศาสตร์ยังคงเป็นเพียงรายการลิงก์ และยากที่จะบอกได้ว่ารายการที่ระบุนี้เป็นการนำทางหลักของเว็บไซต์ คุณเปลี่ยนรายการธรรมดานี้ให้เป็นรายการการนำทางได้โดยการรวม <ul>
ไว้ในองค์ประกอบ <nav>
การใช้องค์ประกอบ <nav>
มีข้อดีหลายประการ ที่เห็นได้ชัดคือโปรแกรมอ่านหน้าจอจะอ่านออกเสียงข้อความว่า "การนำทาง" เมื่อผู้ใช้โต้ตอบกับอุปกรณ์ และเพิ่มจุดสังเกตลงในหน้า จุดสังเกตคือส่วนพิเศษในหน้าเว็บ เช่น <header>
, <footer>
หรือ <main>
ซึ่งโปรแกรมอ่านหน้าจอสามารถข้ามได้ การมีจุดสังเกตในหน้าเว็บจะเป็นประโยชน์เนื่องจากช่วยให้ผู้ใช้โปรแกรมอ่านหน้าจอเข้าถึงภูมิภาคที่สำคัญของหน้าได้โดยตรงโดยไม่ต้องโต้ตอบกับส่วนที่เหลือของหน้า เช่น คุณข้ามจากจุดสังเกตไปยังจุดสังเกตได้โดยกดแป้น D ใน NVDA ใน Voice Over คุณสามารถใช้โรเตอร์เพื่อแสดงจุดสังเกตทั้งหมดในหน้าเว็บโดยกด 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>
ป้ายกำกับที่สั้นกระชับก็เพียงพอแล้ว อย่าใช้คำมากเกินไป ละเว้นการแสดงสีหน้า เช่น "การนำทาง" หรือ "เมนู" เนื่องจากโปรแกรมอ่านหน้าจอให้ข้อมูลนี้อยู่แล้ว
ซ่อนการนำทางในวิวพอร์ตแคบ
โดยส่วนตัวแล้ว ฉันไม่ค่อยชอบการซ่อนการนำทางหลักในวิวพอร์ตแคบๆ แต่ถ้ารายการลิงก์ยาวเกินไป เราก็จะไม่มีทางแก้ได้ หากเป็นเช่นนั้น ผู้ใช้จะเห็นปุ่มที่มีป้ายกำกับว่า "เมนู" แทนที่จะเป็นรายการ หรือไอคอนเบอร์เกอร์ หรือหลายๆ ที่รวมกัน การคลิกปุ่มจะแสดงและซ่อนรายการ ถ้าคุณรู้ 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
เนื่องจากปุ่มควรเป็นองค์ประกอบแรกในการนำทาง หากผู้ใช้แป้นพิมพ์หรือโปรแกรมอ่านหน้าจอกดแท็บหลังจากคลิกปุ่มดังกล่าว ผู้ใช้จะต้องโฟกัสที่รายการแรกในรายการ หากปุ่มอยู่หลังรายการ ปุ่มดังกล่าวจะไม่เป็นเช่นนั้น
ถัดไป คุณต้องรีเซ็ตการจัดรูปแบบเริ่มต้นของปุ่ม แล้วตรวจสอบว่าปุ่มมองเห็นได้ในวิวพอร์ตแบบแคบเท่านั้น
@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;
}
รายการควรมีลักษณะเช่นนี้ในวิวพอร์ตแบบแคบ เหมือนแถบด้านข้างมากกว่ารายการแบบง่าย
สุดท้าย ให้ซ่อนรายการ แสดงเฉพาะเมื่อผู้ใช้คลิกปุ่มหนึ่งครั้ง และซ่อนเมื่อคลิกอีกครั้ง สิ่งสำคัญคือต้องซ่อนเฉพาะรายการ ไม่ใช่การนำทางทั้งหมด เนื่องจากการซ่อนการนำทางจะหมายถึงการซ่อนจุดสังเกตที่สำคัญด้วย
ก่อนหน้านี้คุณได้เพิ่มเหตุการณ์การคลิกลงในปุ่มเพื่อสลับค่าของแอตทริบิวต์ 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
เพื่อสร้างเอฟเฟกต์สไลด์หรือเฟดอินได้ วิธีนี้ใช้ไม่ได้กับจอแสดงผล: ไม่มี เนื่องจากพร็อพเพอร์ตี้การแสดงผลไม่สามารถเคลื่อนไหวได้
การเปลี่ยน 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 (บทบาท) WAI-ARIA 1.1
บทบาทเมนู
เมนูมักจะเป็นรายการการทำงานหรือฟังก์ชันทั่วไปที่ผู้ใช้สามารถเรียกใช้ได้ บทบาทของเมนูเหมาะสมเมื่อมีการแสดงรายการเมนูในลักษณะที่คล้ายกับเมนูในแอปพลิเคชันเดสก์ท็อป
เมนู (บทบาท) WAI-ARIA 1.1
บทบาทแถบเมนู
การนำเสนอเมนูที่มักจะมองเห็นได้และมักจะแสดงในแนวนอน บทบาทแถบเมนูใช้เพื่อสร้างแถบเมนูที่คล้ายกับที่พบในแอปพลิเคชันบนเดสก์ท็อปของ Windows, Mac และ Gnome แถบเมนูใช้เพื่อสร้างชุดคำสั่งที่ใช้บ่อยให้สอดคล้องกัน ผู้เขียนควรตรวจสอบว่าการโต้ตอบของแถบเมนูคล้ายกับการโต้ตอบปกติของแถบเมนูในอินเทอร์เฟซผู้ใช้แบบกราฟิกบนเดสก์ท็อป
แถบเมนู (บทบาท) WAI-ARIA 1.1
บทบาทรายการเมนู
ตัวเลือกในชุดตัวเลือกที่มีเมนูหรือแถบเมนู
เมนูรายการ (บทบาท) 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 ได้
เมื่อสร้างเมนูและแถบเมนู ต้องพิจารณาหลายเรื่องว่าควรใช้เมนูและแถบเมนูตั้งแต่แรกหรือไม่ เมื่อคุณสร้างเว็บไซต์ทั่วไป คุณต้องมีองค์ประกอบการนำทางที่มีรายการและลิงก์ด้วย ซึ่งรวมถึงแอปพลิเคชันหน้าเว็บเดียว (SPA) หรือเว็บแอป สแต็กที่สําคัญจะเป็นข้อมูลใดก็ได้ หลีกเลี่ยงบทบาทในเมนู เว้นแต่คุณจะกำลังสร้างสิ่งที่ใกล้เคียงกับแอปพลิเคชันบนเดสก์ท็อปมาก
แหล่งข้อมูลเพิ่มเติม
- การแก้ไขรายการ โดย Scott O'hara
- Don't Use ARIA Menu Roles for Site Nav โดย Adrian Roselli
- เมนูและ ปุ่มเมนู โดย Heydon Pickering
- เมนู WAI-ARIA และเหตุผลที่คุณควรจัดการด้วยความระมัดระวังโดย Marco Zehe
- การซ่อนเนื้อหาอย่างมีความรับผิดชอบโดย Kitty Giraudel
- :Focus-visible Is Here โดย Matthias Ott
รูปภาพหลักโดย Mick Haupt