ภาพรวมพื้นฐานของวิธีสร้างการนำทางด้านข้างของสไลด์ที่ปรับเปลี่ยนตามอุปกรณ์
ในโพสต์นี้ ผมอยากจะแชร์กับคุณว่า ผมได้สร้างต้นแบบของคอมโพเนนต์ Sidenav สำหรับเว็บซึ่ง ตอบสนองดี เก็บสถานะ รองรับการไปยังส่วนต่างๆ ด้วยแป้นพิมพ์ ทำงานได้ทั้งกับและไม่มี JavaScript และทำงานข้ามเบราว์เซอร์ได้ ทดลองใช้การสาธิต
หากต้องการดูวิดีโอ โปรดใช้โพสต์นี้ในเวอร์ชัน YouTube
ภาพรวม
การสร้างระบบการนำทางที่ปรับเปลี่ยนตามอุปกรณ์นั้นเป็นเรื่องยาก ผู้ใช้บางคนจะใช้แป้นพิมพ์ บางคนจะมีเดสก์ท็อปที่ทรงพลัง และบางคนก็เข้าชมจากอุปกรณ์เคลื่อนที่ขนาดเล็ก ทุกคนที่เข้าชมควรเปิดและปิดเมนูได้
กลยุทธ์สำหรับเว็บ
ในการสำรวจคอมโพเนนต์นี้ ฉันมีความสุขที่ได้รวมฟีเจอร์สำคัญๆ ของแพลตฟอร์มเว็บเอาไว้ ดังนี้
- CSS
:target
- ตารางกริด CSS
- การเปลี่ยนรูปแบบ CSS
- คำค้นหาสื่อ CSS สำหรับวิวพอร์ตและค่ากำหนดของผู้ใช้
- JS สำหรับ
focus
การเพิ่มประสิทธิภาพ UX
โซลูชันของฉันมีแถบด้านข้างเดียวและสลับเฉพาะเมื่ออยู่ที่ "อุปกรณ์เคลื่อนที่" วิวพอร์ตขนาดไม่เกิน 540px
540px
จะเป็นเบรกพอยท์ของเราสำหรับการสลับระหว่างเลย์เอาต์แบบอินเทอร์แอกทีฟบนอุปกรณ์เคลื่อนที่กับเลย์เอาต์เดสก์ท็อปแบบคงที่
คลาสเทียมของ CSS :target
ลิงก์ <a>
1 ลิงก์จะตั้งค่าแฮช URL เป็น #sidenav-open
และอีกลิงก์หนึ่งให้ว่างเปล่า (''
)
สุดท้าย องค์ประกอบมี id
ที่จะจับคู่แฮช
<a href="#sidenav-open" id="sidenav-button" title="Open Menu" aria-label="Open Menu">
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>
<aside id="sidenav-open">
…
</aside>
การคลิกลิงก์แต่ละรายการจะเปลี่ยนสถานะแฮชของ URL หน้าเว็บ จากนั้นด้วยคลาสเทียม ฉันจะแสดงและซ่อนการนำทางด้านข้าง
@media (max-width: 540px) {
#sidenav-open {
visibility: hidden;
}
#sidenav-open:target {
visibility: visible;
}
}
ตารางกริด CSS
ก่อนหน้านี้ฉันใช้ตำแหน่งสัมบูรณ์หรือตำแหน่งคงที่
เลย์เอาต์และคอมโพเนนต์การนำทางด้านข้าง แต่ตารางกริดที่มีไวยากรณ์ grid-area
ช่วยให้เรากำหนดองค์ประกอบหลายรายการให้กับแถวหรือคอลัมน์เดียวกันได้
กลุ่ม
องค์ประกอบการออกแบบหลัก #sidenav-container
คือตารางกริดที่สร้าง 1 แถวและ 2 คอลัมน์
ทั้ง 1 รายการมีชื่อว่า stack
เมื่อพื้นที่ถูกจำกัด CSS จะกำหนดองค์ประกอบ <main>
ทั้งหมด
ย่อยลงในตารางกริดชื่อเดียวกัน โดยวางองค์ประกอบทั้งหมดไว้ในพื้นที่เดียวกันและซ้อนกันเป็นแถว
#sidenav-container {
display: grid;
grid: [stack] 1fr / min-content [stack] 1fr;
min-height: 100vh;
}
@media (max-width: 540px) {
#sidenav-container > * {
grid-area: stack;
}
}
ฉากหลังเมนู
<aside>
เป็นองค์ประกอบที่เคลื่อนไหวซึ่งมีการนำทางด้านข้าง มี
องค์ประกอบย่อย 2 รายการ: คอนเทนเนอร์การนำทาง <nav>
ชื่อ [nav]
และฉากหลัง <a>
ชื่อ [escape]
ซึ่งใช้ในการปิดเมนู
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
ปรับ 2fr
และ 1fr
เพื่อหาอัตราส่วนที่คุณต้องการสำหรับการวางซ้อนเมนูและปุ่มปิดพื้นที่ว่างทางลบ
การแปลง CSS 3 มิติและ ทรานซิชัน
ปัจจุบันเลย์เอาต์ของเราซ้อนกันที่ขนาดวิวพอร์ตของอุปกรณ์เคลื่อนที่ จนกว่าผมจะเพิ่มสไตล์ใหม่ ระบบจะซ้อนทับบทความของเราโดยค่าเริ่มต้น นี่คือ UX บางส่วนที่เราจะถ่ายทำในหัวข้อถัดไป
- แสดงภาพเคลื่อนไหวการเปิดและปิด
- สร้างภาพเคลื่อนไหวแบบภาพเคลื่อนไหวก็ต่อเมื่อผู้ใช้เห็นด้วย
- ทำให้
visibility
เคลื่อนไหวเพื่อไม่ให้โฟกัสแป้นพิมพ์เข้าสู่องค์ประกอบนอกหน้าจอ
เมื่อเริ่มใช้ภาพเคลื่อนไหวที่เคลื่อนไหวได้ ฉันอยากเริ่มจากการช่วยเหลือพิเศษเป็นอันดับต้นๆ
การเคลื่อนไหวที่เข้าถึงได้
อย่างไรก็ตาม ไม่ใช่ทุกคนที่ต้องการรับชมภาพเคลื่อนไหวแบบเลื่อนออก ในโซลูชันของเรา ค่ากำหนดนี้
จะใช้โดยการปรับตัวแปร CSS --duration
ภายในคิวรี่สื่อ ค่าคิวรี่สื่อนี้แสดง
ค่ากำหนดระบบปฏิบัติการของผู้ใช้สำหรับการเคลื่อนไหว (หากมี)
#sidenav-open {
--duration: .6s;
}
@media (prefers-reduced-motion: reduce) {
#sidenav-open {
--duration: 1ms;
}
}
ตอนนี้เมื่อการนำทางด้านข้างของเราเลื่อนเปิดและปิด หากผู้ใช้ต้องการลดการเคลื่อนไหว ผมก็จะย้ายองค์ประกอบเข้ามาในมุมมองทันที โดยคงสถานะไว้โดยไม่มีการเคลื่อนไหว
การเปลี่ยน, การแปลง, การแปล
นำทางออกด้านข้าง (ค่าเริ่มต้น)
หากต้องการตั้งค่าสถานะเริ่มต้นของการนำทางด้านข้างบนอุปกรณ์เคลื่อนที่ให้เป็นสถานะนอกหน้าจอ
ฉันจัดตำแหน่งองค์ประกอบด้วย transform: translateX(-110vw)
หมายเหตุ เราได้เพิ่มอีก 10vw
ในโค้ดทั่วไปของหน้าจอ -100vw
เพื่อให้มั่นใจว่า box-shadow
ของการนำทางด้านข้างจะไม่แอบเข้าไปในวิวพอร์ตหลักเมื่อถูกซ่อนไว้
@media (max-width: 540px) {
#sidenav-open {
visibility: hidden;
transform: translateX(-110vw);
will-change: transform;
transition:
transform var(--duration) var(--easeOutExpo),
visibility 0s linear var(--duration);
}
}
การนำทางด้านข้างใน
เมื่อองค์ประกอบ #sidenav
ตรงกับ :target
ให้กำหนดตำแหน่ง translateX()
เป็น homebase 0
และดูเมื่อ CSS เลื่อนองค์ประกอบจากตำแหน่งที่ออกของ -110vw
ไปยัง "เข้า"
ตำแหน่ง 0
บน var(--duration)
เมื่อเปลี่ยนแฮช URL
@media (max-width: 540px) {
#sidenav-open:target {
visibility: visible;
transform: translateX(0);
transition:
transform var(--duration) var(--easeOutExpo);
}
}
การเปิดเผยการเปลี่ยน
เป้าหมายตอนนี้คือการซ่อนเมนูจากโปรแกรมอ่านหน้าจอเมื่อเผยแพร่อาหาร
เพื่อไม่ให้ระบบโฟกัสอยู่ในเมนูนอกหน้าจอ ฉันสามารถทำได้โดยการตั้งค่า
เปลี่ยนระดับการเข้าถึงเมื่อ :target
เปลี่ยนแปลง
- เมื่อเข้าไปในระบบ อย่าเปลี่ยนระยะการมองเห็น แสดงได้ทันที เพื่อให้ผมเห็นองค์ประกอบที่เลื่อนเข้ามาและเข้าสู่โฟกัส
- เมื่อออกจากบ้าน ให้มองเห็นการเปลี่ยนอุปกรณ์ได้แต่หน่วงเวลา เพื่อให้เปลี่ยนไปเป็น
hidden
เมื่อสิ้นสุดการเปลี่ยน
การเพิ่มประสิทธิภาพ UX สำหรับการช่วยเหลือพิเศษ
ลิงก์
โซลูชันนี้อาศัยการเปลี่ยน URL เพื่อให้จัดการสถานะได้
ตามปกติแล้ว ควรใช้องค์ประกอบ <a>
ที่นี่ และมีการช่วยเหลือพิเศษที่ดี
ฟีเจอร์ได้ฟรี เรามาลองใส่องค์ประกอบแบบอินเทอร์แอกทีฟของเราด้วยป้ายกำกับที่บ่งบอกถึงเจตนากันอย่างชัดเจนกัน
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
<svg>...</svg>
</a>
ตอนนี้ปุ่มโต้ตอบหลักของเราจะระบุเจตนาของปุ่มดังกล่าวสำหรับทั้งเมาส์และแป้นพิมพ์ได้อย่างชัดเจน
:is(:hover, :focus)
ตัวเลือกเทียมซึ่งทำงานของ CSS ที่มีประโยชน์นี้ช่วยให้เรารวมทุกอย่างได้อย่างรวดเร็ว โดยใช้รูปแบบการวางเมาส์โดยแชร์อย่างมุ่งเน้นได้ด้วย
.hamburger:is(:hover, :focus) svg > line {
stroke: hsl(var(--brandHSL));
}
ที่เพิ่มขึ้นใน JavaScript
กด escape
เพื่อปิด
แป้น Escape
บนแป้นพิมพ์ควรปิดเมนูใช่ไหม มาเริ่มกันเลย
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', event => {
if (event.code === 'Escape') document.location.hash = '';
});
ประวัติการเข้าชมของเบราว์เซอร์
เพื่อป้องกันไม่ให้การโต้ตอบแบบเปิดและปิดซ้อนทับกัน ในประวัติการเข้าชมของเบราว์เซอร์ ให้เพิ่ม JavaScript ต่อไปนี้ในบรรทัดไปยัง ปุ่มปิด:
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu" onchange="history.go(-1)"></a>
ซึ่งจะนำรายการประวัติ URL ออกเมื่อปิด ทำให้เหมือนกับว่าเมนู ไม่เคยเปิด
โฟกัส UX
ตัวอย่างถัดไปช่วยให้เราให้ความสำคัญกับปุ่มเปิดและปิดหลังจากที่ เปิดหรือปิด ฉันอยากให้การสลับไปมาเป็นเรื่องง่าย
sidenav.addEventListener('transitionend', e => {
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? document.querySelector('#sidenav-close').focus()
: document.querySelector('#sidenav-button').focus();
})
เมื่อการนำทางด้านข้างเปิดขึ้น ให้โฟกัสที่ปุ่มปิด เมื่อการนำทางด้านข้างปิดลง
โฟกัสปุ่มเปิด ซึ่งทำได้ด้วยการเรียก focus()
บนองค์ประกอบนั้นใน JavaScript
บทสรุป
เมื่อรู้แล้วว่าฉันทำแบบนั้นได้อย่างไร คุณจะทำอย่างไร วิธีนี้ทำให้สถาปัตยกรรมคอมโพเนนต์สนุกขึ้นไปอีกขั้น ใครที่จะทำให้เวอร์ชันแรกมีสล็อต 🙂
มาเพิ่มความหลากหลาย และเรียนรู้วิธีทั้งหมดในการสร้างเนื้อหาบนเว็บ สร้าง Glitch ทวีตให้ฉันเกี่ยวกับเวอร์ชันของคุณ แล้วฉันจะเพิ่มลงใน ส่วนรีมิกซ์ของชุมชนด้านล่าง
รีมิกซ์ในชุมชน
- @_developit พร้อมองค์ประกอบที่กำหนดเอง: demo & รหัส
- @mayeedwin1 กับ HTML/CSS/JS: การสาธิตและ รหัส
- @a_nurella ที่มีรีมิกซ์ Glitch: การสาธิตและ รหัส
- @EvroMalarkey พร้อม HTML/CSS/JS: การสาธิตและ รหัส