ภาพรวมพื้นฐานเกี่ยวกับวิธีสร้างคอมโพเนนต์เบรดครัมบ์ที่ตอบสนองและเข้าถึงได้เพื่อให้ผู้ใช้ไปยังส่วนต่างๆ ของเว็บไซต์ได้
ในโพสต์นี้ เราต้องการแชร์แนวคิดเกี่ยวกับวิธีสร้างคอมโพเนนต์เบรดครัมบ์ ลองใช้เดโม
หากต้องการดูวิดีโอ โปรดดูโพสต์เวอร์ชัน 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 ของ 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>
กำหนดเพียงครั้งเดียว ใช้ได้หลายครั้งตามต้องการ โดยที่ส่งผลกระทบต่อประสิทธิภาพหน้าเว็บน้อยที่สุดและจัดสไตล์ได้อย่างยืดหยุ่น ระบบจะเพิ่มการแจ้งเตือน aria-hidden="true"
ลงในองค์ประกอบ SVG
ไอคอนเหล่านี้ไม่มีประโยชน์สำหรับผู้ที่กําลังเรียกดูเนื้อหาโดยฟังอย่างเดียว การซ่อนไอคอนจากผู้ใช้เหล่านั้นจะช่วยป้องกันไม่ให้ผู้ใช้เพิ่มเสียงรบกวนที่ไม่จำเป็น
ลิงก์แยก .crumb
ตรงนี้เป็นจุดที่เบรดครัมบ์แบบดั้งเดิมและเบรดครัมบ์ในคอมโพเนนต์นี้แตกต่างกัน
โดยปกตินี่จะเป็นลิงก์ <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 แอตทริบิวต์หนึ่งให้บริบทของปุ่มแก่ผู้ใช้หลายคน
การตกแต่งตัวคั่น
<span class="crumb-separator" aria-hidden="true">→</span>
คุณจะใช้ตัวคั่นหรือไม่ก็ได้ การเพิ่มตัวคั่นเพียงเส้นเดียวก็ใช้ได้เช่นกัน (ดูตัวอย่างที่ 3 ในวิดีโอด้านบน) จากนั้นฉันจะใส่ aria-hidden="true"
แต่ละรายการ เนื่องจากเป็นองค์ประกอบตกแต่งและไม่ใช่สิ่งที่โปรแกรมอ่านหน้าจอต้องอ่าน
พร็อพเพอร์ตี้ gap
ในหัวข้อถัดไปจะช่วยให้ระยะห่างของรายการเหล่านี้ไม่ซับซ้อน
รูปแบบ
เนื่องจากสีใช้สีของระบบ ส่วนใหญ่จึงจะเป็นช่องว่างและกองซ้อนสำหรับสไตล์
ทิศทางและโฟลว์ของเลย์เอาต์
องค์ประกอบการนําทางหลัก nav.breadcrumbs
จะตั้งค่าพร็อพเพอร์ตี้ที่กําหนดเองระดับขอบเขตเพื่อให้องค์ประกอบย่อยใช้ หรือจะสร้างเลย์เอาต์แนวนอนที่ปรับแนวตั้งก็ได้ วิธีนี้ช่วยให้เศษขนมปัง ตัวแบ่ง และไอคอนอยู่ในแนวเดียวกัน
.breadcrumbs {
--nav-gap: 2ch;
display: flex;
align-items: center;
gap: var(--nav-gap);
padding: calc(var(--nav-gap) / 2);
}
.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>
ที่ "แทบจะมองไม่เห็น"
.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;
}}
}
สไตล์การแสดงผลที่ overflow จะสร้าง UX ดังต่อไปนี้
- การเลื่อนในแนวนอนที่มีการจำกัดการเลื่อนเกิน
- ระยะห่างจากขอบของการเลื่อนแนวนอน
- จุดยึด 1 จุดบนเศษข้อมูลสุดท้าย ซึ่งหมายความว่าเมื่อโหลดหน้าเว็บ Crumb แรกจะโหลดและแสดงในมุมมอง
- นำจุดสแนปออกจาก 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>
เริ่มทํางาน
บทสรุป
ตอนนี้คุณก็รู้แล้วว่าฉันทำท่านั้นได้อย่างไร คุณจะทำยังไงบ้างคะ‽ 🙂
มาลองใช้แนวทางที่หลากหลายและดูวิธีทั้งหมดในการสร้างบนเว็บกัน สร้างเดโม แล้วทวีตลิงก์มาหาเรา เราจะเพิ่มลงในส่วนรีมิกซ์ของชุมชนด้านล่าง
รีมิกซ์ของชุมชน
- Tux Solbakk เป็นคอมโพเนนต์เว็บ: การสาธิตและโค้ด