การสร้างการนําทางหลักสําหรับเว็บไซต์

บทแนะนำนี้อธิบายวิธีสร้างการนำทางหลักที่เข้าถึงได้ของเว็บไซต์ คุณจะได้เรียนรู้เกี่ยวกับ HTML เชิงความหมาย การช่วยเหลือพิเศษ และวิธีที่การใช้แอตทริบิวต์ ARIA อาจส่งผลเสียมากกว่าผลดีในบางครั้ง

Manuel Matuzović
Manuel Matuzović

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

สำหรับเว็บไซต์ส่วนใหญ่ คุณควรสร้างเว็บไซต์ที่ไม่เรียบง่ายหรือซับซ้อนจนเกินไป

สร้างทีละเลเยอร์

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

โครงสร้างพื้นฐาน

สำหรับการนำทางพื้นฐาน คุณต้องมี 2 สิ่ง ได้แก่ องค์ประกอบ <a> และ CSS 2-3 บรรทัดเพื่อปรับปรุงการจัดรูปแบบและเลย์เอาต์เริ่มต้นของลิงก์

  • HTML

    <a href="/home">Home</a>
    <a href="/about-us">About us</a>
    <a href="/pricing">Pricing</a>
    <a href="/contact">Contact</a>
    
  • CSS

    /* 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);
    }
    
ดูขั้นตอนที่ 1: HTML พื้นฐานและ CSS" ใน CodePen

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

คุณสามารถดำเนินการได้ดังนี้

  • ไฮไลต์หน้าที่ใช้งานอยู่
  • ประกาศจำนวนรายการให้ผู้ใช้โปรแกรมอ่านหน้าจอทราบ
  • เพิ่มจุดสังเกตและอนุญาตให้ผู้ใช้โปรแกรมอ่านหน้าจอเข้าถึงการนำทางได้โดยตรงโดยใช้แป้นพิมพ์ลัด
  • ซ่อนการนำทางในวิวพอร์ตแคบ
  • ปรับปรุงการจัดรูปแบบโฟกัส

ไฮไลต์หน้าที่ใช้งานอยู่

หากต้องการไฮไลต์หน้าที่ใช้งานอยู่ คุณสามารถเพิ่มคลาสลงในลิงก์ที่เกี่ยวข้องได้

<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);
}
ดูขั้นตอนที่ 2: ไฮไลต์หน้าที่ใช้งานอยู่ใน CodePen

ประกาศจำนวนรายการ

เมื่อดูที่การนำทาง ผู้ใช้ที่มองเห็นจะบอกได้ว่ามีลิงก์เพียง 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>
ดูขั้นตอนที่ 3: การประกาศจำนวนรายการใน CodePen

เพิ่มจุดสังเกต

คุณได้ปรับปรุงการใช้งานสำหรับผู้ใช้โปรแกรมอ่านหน้าจอได้อย่างมากโดยไม่ต้องใช้ความพยายามมากนัก แต่ยังมีอีกสิ่งหนึ่งที่คุณทำได้ การนำทางยังคงเป็นเพียงรายการลิงก์ในเชิงความหมาย และเป็นการยากที่จะบอกว่ารายการที่เฉพาะเจาะจงนี้เป็นการนำทางหลักของเว็บไซต์ คุณสามารถเปลี่ยนรายการธรรมดานี้เป็นรายการการนำทางได้โดยการรวม <ul> ไว้ในองค์ประกอบ <nav>

การใช้องค์ประกอบ <nav> มีข้อดีหลายประการ โดยเฉพาะอย่างยิ่ง โปรแกรมอ่านหน้าจอจะประกาศข้อความ เช่น "การนำทาง" เมื่อผู้ใช้โต้ตอบกับองค์ประกอบดังกล่าว และจะเพิ่มจุดสังเกตลงในหน้าเว็บ แลนด์มาร์กคือส่วนพิเศษในหน้าเว็บ เช่น <header>, <footer> หรือ <main> ซึ่งโปรแกรมอ่านหน้าจอสามารถข้ามไปได้ การมีจุดสังเกตในหน้าเว็บอาจเป็นประโยชน์ เนื่องจากช่วยให้ผู้ใช้โปรแกรมอ่านหน้าจอเข้าถึงส่วนสำคัญในหน้าเว็บได้โดยตรงโดยไม่ต้องโต้ตอบกับส่วนที่เหลือของหน้าเว็บ เช่น คุณสามารถข้ามจากจุดสังเกตหนึ่งไปยังอีกจุดสังเกตหนึ่งได้โดยกดแป้น D ใน NVDA ใน VoiceOver คุณสามารถใช้โรเตอร์เพื่อแสดงรายการจุดสังเกตทั้งหมดในหน้าได้โดยกด VO + U

รายการจุดสังเกต 4 รายการ ได้แก่ แบนเนอร์ การนำทาง หลัก ข้อมูลเนื้อหา
โรเตอร์ใน VoiceOver แสดงจุดสังเกตทั้งหมดในหน้าเว็บ

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

หากคุณมีการนําทางทั้งเว็บไซต์ การนําทางในเครื่องสําหรับหน้าเว็บ และการแบ่งหน้าในหน้าเดียว คุณอาจมีองค์ประกอบ <nav> 3 รายการด้วย ซึ่งก็ไม่เป็นไร แต่ตอนนี้มีจุดสังเกตการนำทาง 3 จุด และในทางความหมายแล้วจุดสังเกตทั้งหมดจะดูเหมือนกัน ซึ่งแยกความแตกต่างได้ยาก เว้นแต่คุณจะรู้จักโครงสร้างของหน้าเว็บเป็นอย่างดี

รูปภาพแสดงจุดสังเกต 3 จุดที่ทั้งหมดระบุว่า &quot;การนำทาง&quot;
โรเตอร์ใน VoiceOver แสดงจุดสังเกตการนำทางที่ไม่มีป้ายกำกับ 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>

ป้ายกำกับที่กระชับก็เพียงพอแล้ว อย่าใช้คำฟุ่มเฟือยเกินไป ละเว้นนิพจน์ เช่น "การนำทาง" หรือ "เมนู" เนื่องจากโปรแกรมอ่านหน้าจอให้ข้อมูลนี้แก่ผู้ใช้อยู่แล้ว

จุดสังเกต
VoiceOver แสดงรายการจุดสังเกต "แบนเนอร์" "การนำทางหลัก" "หลัก" "การนำทางหน้าเว็บ" "เลือกการนำทางหน้าเว็บ" และ "ข้อมูลเนื้อหา"
ดูขั้นตอนที่ 4: การเพิ่มจุดสังเกตใน CodePen

ซ่อนการนำทางในวิวพอร์ตแคบ

โดยส่วนตัวแล้ว ฉันไม่ชอบซ่อนการนำทางหลักในวิวพอร์ตแคบๆ แต่หากรายการลิงก์ยาวเกินไป ก็ไม่มีทางเลือกอื่น ในกรณีนี้ ผู้ใช้จะเห็นปุ่มที่มีป้ายกำกับว่า "เมนู" หรือไอคอนแฮมเบอร์เกอร์ หรือทั้ง 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>
  1. แอตทริบิวต์ aria-expanded จะบอกซอฟต์แวร์โปรแกรมอ่านหน้าจอว่าองค์ประกอบที่ปุ่มควบคุมนั้นขยายอยู่หรือไม่
  2. aria-label จะตั้งชื่อที่เข้าถึงได้ให้กับปุ่ม ซึ่งเป็นข้อความแสดงแทนสำหรับไอคอนแฮมเบอร์เกอร์
  3. คุณซ่อน <svg> จากเทคโนโลยีความช่วยเหลือพิเศษโดยใช้ aria-hidden เนื่องจากมีป้ายกำกับข้อความที่ aria-label ระบุไว้แล้ว
  4. 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);
  1. ผู้ใช้จะปิดการนำทางได้ทุกเมื่อที่ต้องการ เช่น โดยการกดแป้น Escape
  2. คุณควรใช้ insertBefore แทน appendChild เนื่องจากปุ่มควรเป็นองค์ประกอบแรกในการนำทาง หากผู้ใช้แป้นพิมพ์หรือโปรแกรมอ่านหน้าจอกด Tab หลังจากคลิกปุ่ม ผู้ใช้จะคาดหวังให้โฟกัสที่รายการแรกในรายการ แต่หากปุ่มอยู่หลังรายการ ก็จะไม่เป็นเช่นนั้น

ถัดไป คุณจะรีเซ็ตการจัดรูปแบบเริ่มต้นของปุ่มและตรวจสอบว่าปุ่มจะปรากฏเฉพาะในวิวพอร์ตแคบๆ เท่านั้น

@media (min-width: 48em) {
  nav {
    --nav-button-display: none;
  }
}

/* Reset button styling */
button {
  all: unset;
  display: var(--nav-button-display, flex);
}
ดูขั้นตอนที่ 5: การเพิ่มปุ่มเบอร์เกอร์ใน CodePen

การซ่อนรายการ

ก่อนที่จะซ่อนรายการ ให้จัดตำแหน่งและจัดสไตล์การนำทางและรายการเพื่อให้เลย์เอาต์ได้รับการเพิ่มประสิทธิภาพสำหรับวิวพอร์ตแคบ แต่ยังคงดูดีบนหน้าจอขนาดใหญ่
ก่อนอื่น ให้นำ <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 จะซ่อนองค์ประกอบดังกล่าวไม่ให้มองเห็นและทำให้เข้าถึงไม่ได้ จึงเป็นการซ่อนองค์ประกอบจากผู้ใช้ทุกคน

ดูขั้นตอนที่ 6: การซ่อนรายการ

การสร้างภาพเคลื่อนไหวให้กับรายการ

หากคุณสงสัยว่าทำไมจึงควรใช้ 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);
}

วิธีนี้ช่วยให้มั่นใจได้ว่าเฉพาะผู้ที่ไม่มีค่ากำหนดสำหรับการลดการเคลื่อนไหวเท่านั้นที่จะเห็นภาพเคลื่อนไหว

ดูขั้นตอนที่ 7: การสร้างภาพเคลื่อนไหวของรายการใน CodePen

ปรับปรุงการจัดรูปแบบโฟกัส

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

ต่อไปนี้คือลักษณะของรูปแบบโฟกัสเริ่มต้นในลิงก์ใน Chrome 103

เส้นขอบสีน้ำเงินขนาด 2 พิกเซลรอบลิงก์ที่โฟกัสใน 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

Browser Support

  • Chrome: 86.
  • Edge: 86.
  • Firefox: 85.
  • Safari: 15.4.

Source

เส้นขอบสีเข้มขนาด 2 พิกเซลที่มองเห็นได้ชัดเจนและมีระยะห่างด้านใน

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

เว็บไซต์ที่มีพื้นหลังสีเข้มและไฮไลต์โฟกัสเป็นสีม่วง
ดูขั้นตอนที่ 8: ปรับปรุงรูปแบบโฟกัสใน CodePen

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

คุณปรับปรุงสิ่งต่างๆ ได้เสมอ เช่น

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

หากคุณจำได้ว่าบทความนี้เริ่มต้นอย่างไร โดยมีเป้าหมายว่าโซลูชันไม่ควร "เรียบง่ายเกินไปหรือซับซ้อนเกินไป" นั่นคือจุดที่เราอยู่ตอนนี้ อย่างไรก็ตาม การออกแบบการนำทางที่ซับซ้อนเกินไปก็อาจเกิดขึ้นได้

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

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

บทบาทการนำทาง

คอลเล็กชันองค์ประกอบการนำทาง (โดยปกติจะเป็นลิงก์) สำหรับไปยังส่วนต่างๆ ของเอกสารหรือเอกสารที่เกี่ยวข้อง

navigation (role) WAI-ARIA 1.1

บทบาทของเมนู

เมนูมักจะเป็นรายการการดำเนินการหรือฟังก์ชันทั่วไปที่ผู้ใช้เรียกใช้ได้ บทบาทเมนูจะเหมาะสมเมื่อมีการแสดงรายการเมนูในลักษณะที่คล้ายกับเมนูในแอปพลิเคชันบนเดสก์ท็อป

menu (role) WAI-ARIA 1.1

บทบาทแถบเมนู

การแสดงเมนูที่มักจะมองเห็นได้และมักจะแสดงในแนวนอน บทบาท menubar ใช้เพื่อสร้างแถบเมนูที่คล้ายกับที่พบในแอปพลิเคชันเดสก์ท็อปของ 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) หรือเว็บแอปด้วย สแต็กที่สำคัญไม่สำคัญ หลีกเลี่ยงบทบาทเมนู เว้นแต่คุณจะสร้างสิ่งที่ใกล้เคียงกับแอปพลิเคชันบนเดสก์ท็อปมาก

แหล่งข้อมูลเพิ่มเติม