ภาพรวมพื้นฐานของวิธีสร้างสไลด์นำทางที่ตอบสนองตามอุปกรณ์
ในโพสต์นี้ ผมจะเล่าให้ฟังถึงวิธีที่ผมสร้างต้นแบบคอมโพเนนต์ Sidenav สำหรับเว็บ ที่ตอบสนองได้ทุกสถานะ รองรับการไปยังส่วนต่างๆ ด้วยแป้นพิมพ์ ทำงานกับและไม่ใช้ JavaScript และทำงานในเบราว์เซอร์ต่างๆ ได้ ทดลองใช้การสาธิต
หากชอบวิดีโอ นี่คือโพสต์นี้เวอร์ชัน YouTube
ภาพรวม
การสร้างระบบการนำทางที่ปรับเปลี่ยนตามอุปกรณ์นั้นเป็นเรื่องยาก ผู้ใช้บางรายจะใช้แป้นพิมพ์ บางคนใช้เดสก์ท็อปที่มีประสิทธิภาพ และบางคนเข้าชมจากอุปกรณ์เคลื่อนที่ขนาดเล็ก ทุกคนที่เข้าชมควรเปิดและปิดเมนูได้
กลยุทธ์สำหรับเว็บ
ในการสำรวจคอมโพเนนต์นี้ ฉันสนุกกับการรวมฟีเจอร์แพลตฟอร์มเว็บที่สำคัญ 2-3 รายการ ได้แก่
- CSS
:target
- ตารางกริด CSS
- transformsของ CSS
- CSS Media Query สำหรับวิวพอร์ตและค่ากำหนดของผู้ใช้
- JS สำหรับ การเพิ่มประสิทธิภาพ UX ของ
focus
โซลูชันของฉันมีแถบด้านข้าง 1 แถบและสลับเปิด/ปิดเฉพาะเมื่ออยู่ที่วิวพอร์ต "อุปกรณ์เคลื่อนที่" ที่ 540px
หรือน้อยกว่า
540px
จะเป็นจุดพักสำหรับการสลับระหว่างเลย์เอาต์แบบอินเทอร์แอกทีฟสำหรับอุปกรณ์เคลื่อนที่กับเลย์เอาต์เดสก์ท็อปแบบคงที่
คลาสเทียมของ CSS :target
ลิงก์ <a>
หนึ่งลิงก์ตั้งค่าแฮช 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
เพื่อหาอัตราส่วนที่คุณต้องการสำหรับการวางซ้อนเมนูและปุ่มปิดพื้นที่ลบ
การแปลงและการเปลี่ยนแบบ 3D ของ CSS
ตอนนี้เลย์เอาต์ของเราจะซ้อนกันที่ขนาดวิวพอร์ตบนอุปกรณ์เคลื่อนที่ ผมจะซ้อนทับบทความของเราโดยค่าเริ่มต้นจนกว่าผมจะเพิ่มสไตล์ใหม่ๆ ตัวอย่าง 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
บทสรุป
ตอนนี้คุณก็รู้แล้วว่าผมทำยังไงแล้วคุณล่ะ คุณจะต้องทำอย่างไร วิธีนี้ทำให้โครงสร้างคอมโพเนนต์สนุกขึ้นได้ ใครจะเป็นผู้สร้างเวอร์ชันแรกที่มีสล็อต 🙂
มาเพิ่มความหลากหลายให้กับวิธีการของเรา และเรียนรู้ทุกวิธีในการสร้างเว็บ สร้างกลิทช์ ทวีตฉันถึงเวอร์ชันของคุณ แล้วฉันจะเพิ่มไปยังส่วนรีมิกซ์ของชุมชนด้านล่าง
รีมิกซ์ของชุมชน
- @_developit พร้อมองค์ประกอบที่กำหนดเอง: การสาธิตและโค้ด
- @mayeedwin1 ใน HTML/CSS/JS: การสาธิตและโค้ด
- @a_nurella ด้วย Glitch Remix: การสาธิตและรหัส
- @EvroMalarkey ใน HTML/CSS/JS: การสาธิตและโค้ด