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

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

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

สาธิต

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

เลย์เอาต์

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> เท่านั้น แต่ผมได้เพิ่ม Traversal UX ด้วย แบบซ่อนตัวเลือก ชั้นเรียน .crumb มีหน้าที่วางลิงก์และ แต่ .crumbicon มีหน้าที่ซ้อนไอคอนและเลือก เอลิเมนต์เข้าด้วยกัน ผมเรียกว่า Split Link เพราะทำงานด้วย คล้ายกับปุ่มแยก แต่สำหรับการนำทางหน้าเว็บ

<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 แอตทริบิวต์หนึ่งให้บริบทของปุ่มสำหรับผู้ใช้จำนวนมาก

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

ตารางกริดสำหรับนักพัฒนาเว็บแสดงซ้อนทับปุ่ม โดยที่ทั้งแถวและคอลัมน์
สแต็กที่มีชื่อ

.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 ต่อไปนี้

  • การเลื่อนแนวนอนที่มีการปิดกั้นการเลื่อนเกิน
  • ระยะห่างจากขอบของการเลื่อนแนวนอน
  • จุดกด 1 จุดบนเศษขนมปังชิ้นสุดท้าย ซึ่งหมายความว่าเมื่อโหลดหน้าเว็บ ครัมบ์โหลดที่สแนปและอยู่ในมุมมอง
  • นำจุดเชื่อมต่อออกจาก 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> ตัวเลือก

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

จำเป็นต้องมีการป้องกัน eager Event เนื่องจากมีการใช้ <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> เริ่มทำงาน

บทสรุป

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

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

รีมิกซ์ในชุมชน