Codelab นี้จะสอนวิธีสร้างคอมโพเนนต์เลย์เอาต์การนําทางด้านข้างแบบเลื่อนออกที่ปรับเปลี่ยนตามอุปกรณ์บนเว็บ ระหว่างที่เราสร้างคอมโพเนนต์นี้ เริ่มจาก HTML, CSS แล้วตามด้วย JavaScript
อ่านบล็อกโพสต์การสร้างคอมโพเนนต์แถบด้านข้างเพื่อดูข้อมูลเกี่ยวกับฟีเจอร์แพลตฟอร์มเว็บ CSS ที่เลือกไว้สำหรับสร้างคอมโพเนนต์นี้
ตั้งค่า
- คลิกรีมิกซ์เพื่อแก้ไขเพื่อให้โปรเจ็กต์แก้ไขได้
- เปิด
app/index.html
HTML
ก่อนอื่น ให้ตั้งค่า HTML เบื้องต้นเพื่อให้มีเนื้อหาและช่องสำหรับทำงาน
วาง HTML ต่อไปนี้ลงในแท็ก <body>
<aside></aside>
<main></main>
<aside>
ถือเมนูการนำทางเป็นองค์ประกอบเสริมของ <main>
ซึ่งถือเนื้อหาหน้าหลัก
ถัดไป เราจะเติมองค์ประกอบเชิงความหมายเหล่านั้นด้วยเนื้อหาที่เหลือของหน้า
เพิ่มองค์ประกอบการนำทาง ลิงก์การนำทางบางส่วน และลิงก์ปิดภายในองค์ประกอบ <aside>
<aside>
<nav>
<h4>My</h4>
<a href="#">Dashboard</a>
<a href="#">Profile</a>
<a href="#">Preferences</a>
<a href="#">Archive</a>
<h4>Settings</h4>
<a href="#">Accessibility</a>
<a href="#">Theme</a>
<a href="#">Admin</a>
</nav>
<a href="#"></a>
</aside>
ลิงก์เหมาะที่จะใส่ไว้ในองค์ประกอบ <nav>
และองค์ประกอบ <nav>
เหมาะที่จะใส่ไว้ในแถบด้านข้างของ <aside>
แต่เรายังต้องทำอะไรอีกมากมายเพื่อปรับปรุง
ในองค์ประกอบเนื้อหาหลัก ให้เพิ่มส่วนหัวและบทความเพื่อเก็บเนื้อหาเลย์เอาต์อย่างมีความหมาย
<main>
<header>
<a href="#sidenav-open" class="hamburger">
<svg viewBox="0 0 50 40">
<line x1="0" x2="100%" y1="10%" y2="10%" />
<line x1="0" x2="100%" y1="50%" y2="50%" />
<line x1="0" x2="100%" y1="90%" y2="90%" />
</svg>
</a>
<h1>Site Title</h1>
</header>
<article>
{put some placeholder content here}
</article>
</main>
ส่วนหัวมีลิงก์เปิดเมนู ที่ด้านข้างมีปุ่มปิดด้วย เราจะแสดงและซ่อนองค์ประกอบตามขนาดวิวพอร์ตในเร็วๆ นี้
ในองค์ประกอบ <article>
เราได้วางประโยคตัวยึดตําแหน่ง แทนที่ " ด้วยข้อมูลของคุณเอง หรือวางข้อมูล Lorem ipsum ที่ระบุไว้ด้านล่าง
<h2>Totam Header</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cum consectetur, necessitatibus velit officia ut impedit veritatis temporibus soluta? Totam odit cupiditate facilis nisi sunt hic necessitatibus voluptatem nihil doloribus! Enim.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead Totam Odit</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<h3>Subhead</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
เนื้อหานี้และความยาวของหน้าคือสิ่งที่จะทำให้เลื่อนหน้าเว็บได้เมื่อเกินความสูงของวิวพอร์ต
จนถึงตอนนี้คุณได้เพิ่มองค์ประกอบ "แถบด้านข้าง" ที่มีการนำทาง ลิงก์ และวิธีปิดแถบด้านข้างแล้ว นอกจากนี้ คุณยังเพิ่มส่วนหัว วิธีเปิดแถบด้านข้าง และบทความลงในองค์ประกอบหลักด้วย ข้อความนี้มีความชัดเจน สื่อความหมาย และดูทันสมัยอยู่แล้ว แต่เราทำให้ข้อความนี้ชัดเจนยิ่งขึ้นสำหรับทุกคนได้ ลิงก์ที่เปิดอยู่ในแถบด้านข้างควรมีการทำเครื่องหมายให้ชัดเจนยิ่งขึ้น
เพิ่มแอตทริบิวต์ title
และ aria-label
ในองค์ประกอบลิงก์แบบเปิดส่วนหัว:
<a href="#sidenav-open" class="hamburger">
<a href="#sidenav-open" title="Open Menu" aria-label="Open Menu" class="hamburger">
คุณทำเครื่องหมายไอคอน SVG ที่เปิดอยู่ได้ชัดเจนขึ้นด้วย เพิ่มแอตทริบิวต์ต่อไปนี้ลงใน SVG ภายในองค์ประกอบลิงก์แบบเปิด
<svg viewBox="0 0 50 40">
<svg viewBox="0 0 50 40" role="presentation" focusable="false" aria-label="trigram for heaven symbol">
ลิงก์ปิดในแถบด้านข้างควรมีการทำเครื่องหมายให้ชัดเจนยิ่งขึ้น
เพิ่มแอตทริบิวต์ title
และ aria-label
ลงในองค์ประกอบลิงก์ปิดของแถบด้านข้าง
<a href="#"></a>
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
CSS
ถึงเวลาจัดวางองค์ประกอบ เนื้อหาหลักและแถบด้านข้างเป็นแท็กย่อยโดยตรงของแท็ก <body>
คุณจึงควรเริ่มที่ส่วนนี้
เพิ่ม CSS ต่อไปนี้ลงใน css/sidenav.css
เพื่อให้องค์ประกอบ <body>
จัดวางองค์ประกอบย่อย
body {
display: grid;
grid: [stack] 1fr / min-content [stack] 1fr;
@media (max-width: 540px) {
& > :matches(aside, main) {
grid-area: stack;
}
}
}
เลย์เอาต์นี้หมายความว่าให้สร้างแถวชื่อ stack
ที่มีทุกอย่างอยู่ในนั้น และ 2 คอลัมน์ในแถวนั้น โดยคอลัมน์ที่ 2 มีชื่อว่า stack
ด้วย คอลัมน์ที่ 1 ควรมีขนาดตามความต้องการขั้นต่ำของเนื้อหา ส่วนคอลัมน์ที่ 2 จะใช้พื้นที่ที่เหลือได้
จากนั้น หากในวิวพอร์ตที่จำกัดไว้ที่ 540px
หรือน้อยกว่า ให้วางการนำทางด้านข้างและองค์ประกอบเนื้อหาหลักลงในแถวและคอลัมน์เดียวกัน ทำให้องค์ประกอบทั้งสองซ้อนทับกันในตารางกริดขนาด 1x1
เมื่อใช้ฟังก์ชันการซ้อนที่ตอบสนองตามอุปกรณ์เป็นพื้นฐานแล้ว ตอนนี้เราใช้ประโยชน์จากสถานะของแถบ URL เพื่อสลับการแสดงผลและสไตล์การเปลี่ยนรูปแบบของแถบด้านข้างได้แล้ว
อัปเดตองค์ประกอบ <aside>
กลับเข้ามาใน app/index.html
:
<aside>
<aside id="sidenav-open">
ซึ่งช่วยให้ CSS จับคู่องค์ประกอบกับแฮช URL ได้ ซึ่งสำคัญต่อการใช้งาน :target
ตอนนี้รหัสขององค์ประกอบจะจับคู่กับแฮช URL ที่เรากําลังจะตั้งค่าด้วยแท็ก <a>
นอกจากนี้ เพื่อให้การกำหนดเป้าหมาย JavaScript ง่ายขึ้น ให้เพิ่มรหัสสำหรับองค์ประกอบหลักที่ควบคุมการนำทางด้านข้าง ก่อนอื่น ให้เพิ่มรหัสลงในลิงก์เปิดการนำทางด้านข้าง โดยทำดังนี้
<a href="#sidenav-open" class="hamburger" title="Open Menu" aria-label="Open Menu">
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
ถัดไป เพิ่มรหัสลงในลิงก์ปิดการนำทางด้านข้าง:
<a href="#" title="Close Menu" aria-label="Close Menu"></a>
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>
เท่านี้ก็จบเลยสำหรับมาโคร <body>
เลย์เอาต์การซ้อนที่ตอบสนองได้ รวมถึงการเชื่อมโยงเรากับแถบ URL
มาลุยกันต่อเลย
<aside>
ยังมีเลย์เอาต์ที่เรียบร้อยอีกด้วย องค์ประกอบนี้มีองค์ประกอบย่อย 2 รายการ ได้แก่ <nav>
ซึ่งเป็นคอมโพเนนต์ที่มีลักษณะคล้ายกระดาษซึ่งเลื่อนออกมา และองค์ประกอบลิงก์ <a>
ที่ปิดอยู่ซึ่งตั้งค่า URL เป็น #
ลิงก์ไม่ปรากฏอยู่ทางขวาของกระดาษนำทางที่เลื่อนออก เพื่อให้ผู้ใช้สามารถ "คลิกปิด" องค์ประกอบภาพเพื่อปิดได้
เพิ่ม CSS ต่อไปนี้ลงใน css/sidenav.css
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
}
เราคิดว่าสัดส่วนและชื่อต่างๆ นั้นยอดเยี่ยมมาก ตรงนี้เป็นจุดที่กริดจะแสดงศักยภาพและช่วยให้นักออกแบบควบคุมได้อย่างเต็มที่
ถัดไป เราต้องวางซ้อนเนื้อหาหลักแบบมีเงื่อนไขและคงตำแหน่งไว้ขณะเลื่อนเอกสาร นี่เป็นงานที่ยอดเยี่ยมสำหรับ position: sticky
และ overscroll-behavior
บางราย
เพิ่มรูปแบบต่อไปนี้สำหรับการนำทางด้านข้าง
#sidenav-open {
display: grid;
grid-template-columns: [nav] 2fr [escape] 1fr;
@media (max-width: 540px) {
position: sticky;
top: 0;
max-height: 100vh;
overflow: hidden auto;
overscroll-behavior: contain;
visibility: hidden; /* not keyboard accessible when closed */
}
}
รูปแบบดังกล่าวจะทำให้การนำทางด้านข้างมีความสูงของวิวพอร์ต การเลื่อนในแนวตั้งและมีการเลื่อน และที่สำคัญคือจะซ่อนองค์ประกอบ โดยค่าเริ่มต้น ระบบจะซ่อนแถบด้านข้างนั้นเมื่อวิวพอร์ตมีขนาด 540px
หรือเล็กกว่านั้น ยกเว้นในกรณีต่อไปนี้
เพิ่มตัวเลือกจำลอง :target
ลงในองค์ประกอบ #sidenav-open
#sidenav-open {
@media (max-width: 540px) {
&:target {
visibility: visible;
}
}
}
เมื่อรหัสขององค์ประกอบนั้นและแถบ URL เหมือนกัน ให้ตั้งค่า visibility
เป็น visible
ลองเปิดเมนูด้านข้างหลังจากเลื่อนหน้าเว็บ หรือลองเลื่อนหน้าเว็บขณะที่เมนูด้านข้างเปิดอยู่ คุณมีความคิดเห็นอย่างไร
เพิ่ม CSS ต่อไปนี้ที่ด้านล่างของ app/sidenav.css
#sidenav-button,
#sidenav-close {
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
user-select: none;
touch-action: manipulation;
@media (min-width: 540px) {
display: none;
}
}
สไตล์เหล่านี้กำหนดเป้าหมายไปยังปุ่มเปิดและปิด ระบุสไตล์การแตะและการสัมผัสของปุ่ม และซ่อนปุ่มเมื่อวิวพอร์ตมีขนาด 540px
ขึ้นไป
เพิ่มลูกเล่นด้วยการเปลี่ยนรูปแบบ CSS ที่เข้าถึงได้ง่าย
เพิ่ม CSS ต่อไปนี้ลงใน css/sidenav.css
#sidenav-open {
--easeOutExpo: cubic-bezier(0.16, 1, 0.3, 1);
--duration: .6s;
...
@media (max-width: 540px) {
...
transform: translateX(-110vw);
will-change: transform;
transition:
transform var(--duration) var(--easeOutExpo),
visibility 0s linear var(--duration);
&:target {
visibility: visible;
transform: translateX(0);
transition: transform var(--duration) var(--easeOutExpo);
}
}
@media (prefers-reduced-motion: reduce) {
--duration: 1ms;
}
}
เพิ่มคำลงใน JavaScript บางส่วน
แป้น Escape
ควรปิดเมนู เพิ่ม JS นี้ลงใน js/index.js
const sidenav = document.querySelector('#sidenav-open');
sidenav.addEventListener('keyup', e => {
if (e.code === 'Escape') {
document.location.hash = '';
}
});
ซึ่งจะรอเหตุการณ์สำคัญในองค์ประกอบแถบด้านข้าง
หากเป็น Escape
ระบบจะตั้งค่าแฮช URL เป็นว่าง ทำให้แถบด้านข้างเปลี่ยนสถานะเป็นปิด
UX JS ชิ้นถัดไปคือการจัดการโฟกัส เราต้องการให้เปิดและปิดได้ง่าย จึงรอจนกว่าแถบด้านข้างจะเปลี่ยนรูปแบบเสร็จแล้ว จากนั้นตรวจสอบกับแฮช URL เพื่อดูว่าแถบด้านข้างแสดงอยู่หรือซ่อนอยู่ จากนั้นฉันใช้ JavaScript เพื่อตั้งค่าโฟกัสบนปุ่มที่สอดคล้องกับปุ่มที่ผู้ใช้เพิ่งกด
เพิ่ม JavaScript ต่อไปนี้ลงใน js/index.js
const closenav = document.querySelector('#sidenav-close');
const opennav = document.querySelector('#sidenav-button');
sidenav.addEventListener('transitionend', e => {
if (e.propertyName !== 'transform') {
return;
}
const isOpen = document.location.hash === '#sidenav-open';
isOpen
? closenav.focus()
: opennav.focus();
});
ลองเลย
- หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกดเต็มหน้าจอ
บทสรุป
นี่เป็นสรุปความต้องการเกี่ยวกับคอมโพเนนต์ คุณสามารถใช้ฟีเจอร์นี้ต่อยอด ขับเคลื่อนด้วยสถานะ JavaScript แทน URL และปรับแต่งได้ตามต้องการ นอกจากนี้ยังมีกรณีการใช้งาน มากมายที่ต้องเพิ่มเข้ามาอยู่เสมอ
เปิด css/brandnav.css
เพื่อดูสไตล์ที่ไม่เกี่ยวข้องกับเลย์เอาต์ที่ฉันใช้กับคอมโพเนนต์นี้ ผมรู้สึกว่ามันไม่สำคัญกับชุดคุณลักษณะที่ผมกำลังมุ่งเน้น และผมหวังว่าการแยกสไตล์จากเลย์เอาต์จะช่วยผลักดันให้การคัดลอกและวาง อาจมีการเรียนรู้เพิ่มเติม
สำหรับคุณ!
คุณสร้างคอมโพเนนต์แถบด้านข้างที่ตอบสนองต่อการเลื่อนออกได้อย่างไร คุณเคยมีมากกว่า 1 รายการไหม เช่น มี 1 รายการทั้ง 2 ด้าน เราอยากแสดงวิธีแก้ปัญหาของคุณในวิดีโอ YouTube โปรดทวีตถึงเราหรือแสดงความคิดเห็นใน YouTube พร้อมรหัสของคุณ ซึ่งจะช่วยทุกคนได้