การสร้างคอมโพเนนต์เบรดครัมบ์

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

ในโพสต์นี้ ฉันอยากแชร์วิธีคิดวิธีสร้างคอมโพเนนต์เบรดครัมบ์ ลองใช้เดโม

การสาธิต

หากชอบวิดีโอ นี่คือโพสต์นี้เวอร์ชัน YouTube

ภาพรวม

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

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

UX ในเบื้องหลัง

ในวิดีโอสาธิตคอมโพเนนต์ด้านบน หมวดหมู่ตัวยึดตำแหน่งคือประเภทของวิดีโอเกม เส้นทางนี้สร้างขึ้นโดยการไปยังเส้นทางต่อไปนี้: home » rpg » indie » on sale ดังที่แสดงด้านล่าง

คอมโพเนนต์เบรดครัมบ์นี้ควรช่วยให้ผู้ใช้ไปยังส่วนต่างๆ ของข้อมูลนี้ได้ เช่น การข้ามสาขาและเลือกหน้าด้วยความเร็วและความแม่นยำ

สถาปัตยกรรมข้อมูล

ฉันคิดว่าการมองในแง่ของคอลเล็กชันและสินค้าเป็นเรื่องที่มีประโยชน์

คอลเล็กชัน

คอลเล็กชันคืออาร์เรย์ของตัวเลือกที่มีให้ จากหน้าแรกของต้นแบบเบรดครัมบ์ของโพสต์นี้ คอลเล็กชันต่างๆ ได้แก่ FPS, RPG, นักสู้, โปรแกรมรวบรวมข้อมูลคุกใต้ดิน, กีฬา และเกมปริศนา

รายการ

วิดีโอเกมคือไอเทม คอลเล็กชันที่เฉพาะเจาะจงอาจเป็นไอเทมด้วยหากเป็นคอลเล็กชันอื่น เช่น RPG เป็นไอเทมและคอลเล็กชันที่ถูกต้อง เมื่อเป็นสินค้า ผู้ใช้จะอยู่ในหน้าคอลเล็กชันนั้น ตัวอย่างเช่น การ์ดจะอยู่ในหน้า RPG ซึ่งแสดงรายการเกม RPG รวมถึงหมวดหมู่ย่อยเพิ่มเติมอย่าง AAA, อินดี้ และการเผยแพร่ด้วยตนเอง

ในทางวิทยาการคอมพิวเตอร์ คอมโพเนนต์เบรดครัมบ์นี้แสดงถึงอาร์เรย์หลายมิติ ดังนี้

const rawBreadcrumbData = {
  "FPS": {...},
  "RPG": {
    "AAA": {...},
    "indie": {
      "new": {...},
      "on sale": {...},
      "under 5": {...},
    },
    "self published": {...},
  },
  "brawler": {...},
  "dungeon crawler": {...},
  "sports": {...},
  "puzzle": {...},
}

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

เลย์เอาต์

Markup

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

รูปแบบมืดและสว่าง

<meta name="color-scheme" content="dark light">

เมตาแท็ก color-scheme ในข้อมูลโค้ดด้านบนแจ้งเบราว์เซอร์ว่าหน้านี้ต้องการสไตล์เบราว์เซอร์เป็นแบบสว่างและมืด เบรดครัมบ์ตัวอย่างไม่มี CSS สำหรับรูปแบบสีเหล่านี้ เบรดครัมบ์จะใช้สีเริ่มต้นที่เบราว์เซอร์ระบุไว้

<nav class="breadcrumbs" role="navigation"></nav>

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

ไอคอน

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

หากต้องการใช้เทคนิคนี้ ให้เพิ่มองค์ประกอบ SVG ที่ซ่อนไว้ลงในหน้า แล้วรวมไอคอนไว้ในองค์ประกอบ <symbol> ที่มีรหัสที่ไม่ซ้ำกัน

<svg style="display: none;">

  <symbol id="icon-home">
    <title>A home icon</title>
    <path d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
  </symbol>

  <symbol id="icon-dropdown-arrow">
    <title>A down arrow</title>
    <path d="M19 9l-7 7-7-7"/>
  </symbol>

</svg>

เบราว์เซอร์จะอ่าน SVG HTML, ใส่ข้อมูลไอคอนลงในหน่วยความจำ แล้วดำเนินการต่อกับส่วนที่เหลือของหน้าโดยอ้างอิงรหัสเพื่อใช้ไอคอนเพิ่มเติม เช่น

<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
  <use href="#icon-home" />
</svg>

<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
  <use href="#icon-dropdown-arrow" />
</svg>

เครื่องมือสำหรับนักพัฒนาเว็บแสดงองค์ประกอบการใช้งาน SVG ที่แสดงผลแล้ว

โปรดกำหนดเพียงครั้งเดียว ใช้งานกี่ครั้งก็ได้ โดยมีผลกระทบต่อประสิทธิภาพของหน้าเว็บน้อยที่สุด และการจัดรูปแบบที่ยืดหยุ่น การแจ้งเตือน aria-hidden="true" จะได้รับการเพิ่มลงในองค์ประกอบ SVG ไอคอนจะไม่มีประโยชน์ต่อผู้ที่เรียกดูเฉพาะผู้ที่ได้ยินเนื้อหาเท่านั้น การซ่อนผู้ใช้จากผู้ใช้เหล่านั้นจะทำให้ผู้ใช้ไม่เพิ่มสัญญาณรบกวนที่ไม่จำเป็น

ซึ่งเป็นจุดที่เบรดครัมบ์แบบดั้งเดิมและรายการในคอมโพเนนต์นี้จะแยกออกจากกัน ปกติแล้วนี่เป็นเพียงลิงก์ <a> แต่ฉันได้เพิ่ม UX การส่งผ่านด้วยตัวเลือกแบบซ่อน คลาส .crumb มีหน้าที่จัดวางลิงก์และไอคอน ส่วน .crumbicon จะทำหน้าที่ซ้อนไอคอนและเลือกองค์ประกอบไว้ด้วยกัน ฉันเรียกมันว่าการแยกลิงก์เพราะฟังก์ชันของมันคล้ายกับปุ่มแยกมากๆ แต่ใช้การนำทางหน้าเว็บ

<span class="crumb">
  <a href="#sub-collection-b">Category B</a>
  <span class="crumbicon">
    <svg>...</svg>
    <select class="disguised-select" title="Navigate to another category">
      <option>Category A</option>
      <option selected>Category B</option>
      <option>Category C</option>
    </select>
  </span>
</span>

ลิงก์และตัวเลือกบางอย่างไม่มีอะไรพิเศษ แต่จะเพิ่มฟังก์ชันการทำงานให้กับเบรดครัมบ์ที่เรียบง่าย การเพิ่ม title ลงในองค์ประกอบ <select> มีประโยชน์สำหรับผู้ใช้โปรแกรมอ่านหน้าจอ ซึ่งเป็นการให้ข้อมูลเกี่ยวกับการทำงานของปุ่ม แต่วิธีนี้ก็มอบความช่วยเหลือแบบเดียวกันแก่คนอื่นๆ ด้วย คุณจะเห็นฟีเจอร์นี้แสดงอยู่ด้านหน้า บน iPad แอตทริบิวต์ 1 รายการให้บริบทของปุ่มแก่ผู้ใช้จำนวนมาก

ภาพหน้าจอที่วางเหนือองค์ประกอบ Select ที่มองไม่เห็น และแสดงเคล็ดลับเครื่องมือตามบริบท

การตกแต่งเส้นแบ่ง

<span class="crumb-separator" aria-hidden="true">→</span>

คุณจะใช้ตัวคั่นหรือไม่ก็ได้ การเพิ่มแค่ตัวคั่นเดียวก็ใช้ได้เหมือนกัน (ดูตัวอย่างที่ 3 ในวิดีโอด้านบน) จากนั้นฉันจะให้ aria-hidden="true" แต่ละรายการเนื่องจากเป็นอุปกรณ์ตกแต่ง และไม่ต้องมีโปรแกรมอ่านหน้าจอ

พร็อพเพอร์ตี้ gap ที่ครอบคลุมในลำดับถัดไปจะทำให้ระยะห่างของอักขระเหล่านี้ไม่ซับซ้อน

รูปแบบ

เนื่องจากสีใช้สีของระบบ ซึ่งมักจะเป็นช่องว่างและร่องรอยของสไตล์

ทิศทางและโฟลว์ของเลย์เอาต์

เครื่องมือสำหรับนักพัฒนาเว็บแสดงการปรับเบรดครัมบ์การนำทางด้วยฟีเจอร์การวางซ้อน Flexbox

องค์ประกอบการไปยังส่วนต่างๆ หลัก nav.breadcrumbs จะตั้งค่าพร็อพเพอร์ตี้ที่กำหนดเองที่มีขอบเขตเพื่อให้ผู้เผยแพร่โฆษณาย่อยใช้ได้ หรือสร้างการออกแบบแนวตั้งในแนวนอน วิธีนี้ช่วยให้มั่นใจว่าเศษซาก ตัวแบ่ง และไอคอนจะสอดคล้องกัน

.breadcrumbs {
  --nav-gap: 2ch;

  display: flex;
  align-items: center;
  gap: var(--nav-gap);
  padding: calc(var(--nav-gap) / 2);
}

เบรดครัมบ์ 1 รายการที่แสดงในแนวตั้งพร้อมการวางซ้อน Flexbox

.crumb แต่ละรายการยังสร้างเลย์เอาต์แนวตั้งแนวนอนโดยมีช่องว่างอยู่บ้าง แต่จะกำหนดเป้าหมายพิเศษเฉพาะรายการที่เป็นลิงก์ย่อยและระบุสไตล์ white-space: nowrap ซึ่งสำคัญมากสำหรับเบรดครัมบ์แบบหลายคำ เนื่องจากเราไม่อยากให้แสดงเป็นหลายบรรทัด ภายหลังในโพสต์นี้ เราจะเพิ่มรูปแบบเพื่อจัดการกับส่วนเกินในแนวนอนของพร็อพเพอร์ตี้ white-space นี้

.crumb {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--nav-gap) / 4);

  & > a {
    white-space: nowrap;

    &[aria-current="page"] {
      font-weight: bold;
    }
  }
}

มีการเพิ่ม aria-current="page" เพื่อช่วยให้ลิงก์ของหน้าปัจจุบันโดดเด่นจากลิงก์อื่น นอกจากผู้ใช้โปรแกรมอ่านหน้าจอจะมีสัญญาณบอกสถานะที่ชัดเจนว่าลิงก์มีไว้สำหรับหน้าปัจจุบันแล้ว เรายังได้ออกแบบองค์ประกอบด้วยภาพเพื่อช่วยให้ผู้ใช้ที่มองเห็นได้รับประสบการณ์ของผู้ใช้ที่คล้ายกัน

คอมโพเนนต์ .crumbicon ใช้ตารางกริดเพื่อซ้อนไอคอน SVG ที่มีองค์ประกอบ <select> ที่ "แทบจะมองไม่เห็น"

Grid DevTools แสดงโดยวางซ้อนปุ่มตรงที่เรียงซ้อนชื่อทั้งแถวและคอลัมน์

.crumbicon {
  --crumbicon-size: 3ch;

  display: grid;
  grid: [stack] var(--crumbicon-size) / [stack] var(--crumbicon-size);
  place-items: center;

  & > * {
    grid-area: stack;
  }
}

องค์ประกอบ <select> อยู่ท้ายสุดใน DOM จึงอยู่เหนือกลุ่มที่ซ้อนกันและโต้ตอบได้ เพิ่มสไตล์แบบ opacity: .01 เพื่อให้องค์ประกอบยังคงใช้งานได้ และผลลัพธ์ที่ได้คือช่องสำหรับเลือกที่พอดีกับรูปร่างของไอคอนอย่างลงตัว วิธีนี้เป็นวิธีที่ดีในการปรับแต่งรูปลักษณ์ขององค์ประกอบ <select> โดยยังคงฟังก์ชันการทำงานในตัวเอาไว้

.disguised-select {
  inline-size: 100%;
  block-size: 100%;
  opacity: .01;
  font-size: min(100%, 16px); /* Defaults to 16px; fixes iOS zoom */
}

รายการเพิ่มเติม

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

.breadcrumbs {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: calc(var(--nav-gap) / 2);

  & > .crumb:last-of-type {
    scroll-snap-align: end;
  }

  @supports (-webkit-hyphens:none) { & {
    scroll-snap-type: none;
  }}
}

รูปแบบรายการเพิ่มเติมตั้งค่า UX ต่อไปนี้

  • การเลื่อนในแนวนอนโดยมีการป้องกันการเลื่อนเกิน
  • ระยะห่างจากขอบของการเลื่อนแนวนอน
  • สแนปจุดเดียวที่เศษส่วนสุดท้าย ซึ่งหมายความว่าเมื่อโหลดหน้าเว็บ ครัมบ์แรกจะโหลดโดยสแนปและในมุมมอง
  • นำจุดในการสแนปออกจาก Safari ซึ่งจะเล่นกับเอฟเฟกต์การเลื่อนในแนวนอนและสแนปได้ยาก

การค้นหาสื่อ

การปรับเปลี่ยนเล็กๆ น้อยๆ อย่างหนึ่งสำหรับวิวพอร์ตขนาดเล็กคือการซ่อนป้ายกำกับ "บ้าน" โดยเหลือไว้เพียงไอคอน ดังนี้

@media (width <= 480px) {
  .breadcrumbs .home-label {
    display: none;
  }
}

แสดงด้านข้างของเบรดครัมบ์ที่มีและไม่มีป้ายกำกับหน้าแรก เพื่อการเปรียบเทียบ

การช่วยเหลือพิเศษ

การเคลื่อนไหว

มีการเคลื่อนไหวไม่มากนักในคอมโพเนนต์นี้ แต่การรวมการเปลี่ยนในการตรวจสอบ prefers-reduced-motion จะทำให้เราป้องกันการเคลื่อนไหวที่ไม่พึงประสงค์ได้

@media (prefers-reduced-motion: no-preference) {
  .crumbicon {
    transition: box-shadow .2s ease;
  }
}

รูปแบบอื่นๆ ทั้งหมดไม่จำเป็นต้องเปลี่ยนแปลง เอฟเฟกต์การวางเมาส์และโฟกัสนั้นยอดเยี่ยมและมีความหมายโดยไม่มี transition แต่หากการเคลื่อนไหวได้ไม่ว่าจะเป็นเรื่องใด เราจะเพิ่มการเปลี่ยนฉากลงในการโต้ตอบแบบนุ่มนวล

JavaScript

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

มาตรการด้านประสบการณ์ของผู้ใช้ที่สำคัญ 2 อย่างที่ JavaScript จัดการ ได้แก่ การเลือกได้เปลี่ยนแปลงและป้องกันการเริ่มทำงานของเหตุการณ์การเปลี่ยนแปลง <select> อย่างมาก

จําเป็นต้องมีการป้องกันเหตุการณ์เชิงรุกเนื่องจากการใช้องค์ประกอบ <select> ใน Windows Edge หรือเบราว์เซอร์อื่นๆ ด้วย เหตุการณ์ changed บางรายการจะเริ่มทำงานเมื่อผู้ใช้เรียกดูตัวเลือกด้วยแป้นพิมพ์ นี่จึงเป็นสาเหตุที่ฉันเรียกว่า "มีความกระตือรือร้น" เนื่องจากผู้ใช้เลือกตัวเลือกสมมติเท่านั้น เช่น การวางเมาส์เหนือหรือโฟกัส แต่ยังไม่ได้ยืนยันตัวเลือกด้วย enter หรือ click เหตุการณ์ที่เกิดขึ้นใหม่จะทำให้ไม่สามารถเข้าถึงฟีเจอร์การเปลี่ยนแปลงหมวดหมู่คอมโพเนนต์ได้ เนื่องจากการเปิดช่องและการเรียกดูรายการจะทำให้เหตุการณ์เริ่มทำงานและเปลี่ยนแปลงหน้าเว็บก่อนที่ผู้ใช้จะพร้อม

กิจกรรมการเปลี่ยนแปลงที่ดีขึ้นใน <select>

const crumbs = document.querySelectorAll('.breadcrumbs select')
const allowedKeys = new Set(['Tab', 'Enter', ' '])
const preventedKeys = new Set(['ArrowUp', 'ArrowDown'])

// watch crumbs for changes,
// ensures it's a full value change, not a user exploring options via keyboard
crumbs.forEach(nav => {
  let ignoreChange = false

  nav.addEventListener('change', e => {
    if (ignoreChange) return
    // it's actually changed!
  })

  nav.addEventListener('keydown', ({ key }) => {
    if (preventedKeys.has(key))
      ignoreChange = true
    else if (allowedKeys.has(key))
      ignoreChange = false
  })
})

กลยุทธ์สำหรับวิธีนี้คือเฝ้าติดตามเหตุการณ์การกดแป้นพิมพ์ในองค์ประกอบ <select> แต่ละรายการ และระบุว่าคีย์ที่กดเป็นการยืนยันการนำทาง (Tab หรือ Enter) หรือการไปยังส่วนต่างๆ (ArrowUp หรือ ArrowDown) ตามการพิจารณานี้ คอมโพเนนต์จะเลือกรอหรือไปก็ได้เมื่อเหตุการณ์สำหรับองค์ประกอบ <select> เริ่มทำงาน

บทสรุป

ตอนนี้คุณก็รู้แล้วว่าตัวเองทำยังไง คุณจะทำอะไรบ้าง‽ 🙂

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

รีมิกซ์ของชุมชน