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