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>
ส่วนหัวมีลิงก์เปิดเมนู โดยแถบด้านข้างจะมีปุ่มปิด เราจะแสดงและซ่อนองค์ประกอบตามขนาด Viewport ในเร็วๆ นี้
เราวางประโยคตัวยึดตำแหน่งในองค์ประกอบ <article>
แทนที่ `` ด้วยเนื้อหาของคุณเอง หรือวางข้อความจำลองที่ระบุไว้ด้านล่าง
<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>
เนื้อหาและความยาวของเนื้อหานี้จะทำให้หน้าเว็บเลื่อนได้เมื่อมีความสูงเกินวิวพอร์ต
จนถึงตอนนี้ คุณได้เพิ่มองค์ประกอบ "aside" พร้อมด้วย "nav" ลิงก์ และวิธีปิดแถบด้านข้าง นอกจากนี้ คุณยังเพิ่มส่วนหัว วิธีเปิดแถบนำทางด้านข้าง และบทความลงในองค์ประกอบหลักด้วย โค้ดนี้สะอาด มีความหมาย และดูดีอยู่แล้ว แต่เราสามารถทำให้สะอาดและชัดเจนยิ่งขึ้นสำหรับทุกคนได้ ควรทำเครื่องหมายลิงก์เปิดในแถบนำทางด้านข้างให้ชัดเจนยิ่งขึ้น
เพิ่มแอตทริบิวต์ 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
ด้วย คอลัมน์แรก
ควรมีขนาดตามความต้องการเนื้อหาขั้นต่ำ และคอลัมน์ที่ 2 สามารถใช้พื้นที่ที่เหลือได้
จากนั้นหากอยู่ในวิวพอร์ตที่จำกัดขนาด 540px
หรือน้อยกว่า ให้วางองค์ประกอบแถบด้านข้างและเนื้อหาหลัก
ไว้ในแถวและคอลัมน์เดียวกัน ซึ่งจะทำให้องค์ประกอบทั้ง 2 อยู่ซ้อนกันในตารางกริด 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;
}
}
สไตล์เหล่านี้กำหนดเป้าหมายไปที่ปุ่มเปิดและปิด ระบุสไตล์การแตะและการสัมผัส
และยังซ่อนปุ่มเมื่อ Viewport มีขนาด 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 อันไหม เช่น มีทั้ง 2 ข้าง เราอยากนำเสนอโซลูชันของคุณในวิดีโอ YouTube อย่าลืมทวีตถึงเราหรือแสดงความคิดเห็นใน YouTube พร้อมโค้ดของคุณเพื่อช่วยทุกคน