בשיעור הזה תלמדו איך ליצור באינטרנט רכיב פריסה רספונסיבי של תפריט ניווט צדדי שנפתח בהזזה. נבנה את הרכיב תוך כדי תנועה, נתחיל עם HTML, אחר כך CSS ואז JavaScript.
בפוסט בבלוג Building a Sidenav component אפשר לקרוא על התכונות של פלטפורמת האינטרנט CSS שנבחרו ליצירת הרכיב הזה.
הגדרה
- לוחצים על Remix to Edit כדי להפוך את הפרויקט לעריכה.
- פתיחת
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>
בכותרת יש קישור לפתיחת התפריט. בצד מופיע לחצן הסגירה. בקרוב נציג או נסתיר רכיבים בהתאם לגודל אזור התצוגה.
הדבקנו משפט placeholder ברכיב <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, קישורים ואפשרות לסגירת ה-sidenav. הוספתם גם כותרת, דרך לפתוח את סרגל הצד וכתבה לרכיב הראשי. הקוד הזה נקי, סמנטי ודי נצחי, אבל אפשר להפוך אותו לנקי וברור יותר לכולם. הקישור לפתיחה בסרגל הצד יכול להיות מסומן בצורה ברורה יותר.
מוסיפים את המאפיינים 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 עמודות בשורה הזו, כאשר העמודה השנייה נקראת גם stack
. הגודל של העמודה הראשונה צריך להיות בהתאם לצרכים המינימליים של התוכן שבה, והעמודה השנייה יכולה לתפוס את שאר המקום.
לאחר מכן, אם רוחב אזור התצוגה המוגבל הוא 540px
או פחות, צריך להציב את רכיבי התוכן הראשי והניווט הצדדי באותה שורה ועמודה, כך שהם יוצבו אחד מעל השני ברשת 1x1.
בעזרת הפונקציונליות הזו של סידור רכיבים בתגובה לשינוי גודל המסך, אנחנו יכולים עכשיו להשתמש במצב של סרגל כתובת ה-URL כדי להחליף את הנראות ואת סגנון המעבר של סרגל הצד.
מעדכנים את הרכיב <aside>
בחזרה ב-app/index.html
:
<aside>
<aside id="sidenav-open">
כך שירות ה-CSS יכול להתאים בין אלמנט לבין הגיבוב של כתובת ה-URL. זה חשוב לשימוש ב-:target
.
עכשיו המזהה של הרכיב יכול להתאים לגיבוב (hash) של כתובת ה-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 = '';
}
});
התג הזה מאזין לאירוע מרכזי ברכיב sidenav.
אם הערך הוא Escape
, הפונקציה מגדירה את הגיבוב של כתובת ה-URL כריק, וכך חל מעבר של סרגל הצד החוצה.
החלק הבא של ה-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
כדי לראות את הסגנונות שלא קשורים לפריסה שהגדרתי לרכיב הזה. לא חשבתי שזה חשוב לסט התכונות שהתמקדתי בו, וקיוויתי שהפרדת הסגנונות מהפריסה תעודד העתקה והדבקה. יכול להיות שתמצאו שם עוד חומר לימוד!
איך יוצרים רכיבי סרגל צד רספונסיביים שנשלפים? האם קורה שיש לך יותר מאחד, למשל אחד בכל צד? אשמח להציג את הפתרון שלך בסרטון ב-YouTube. כדי לעשות את זה, תייג אותי בטוויטר או תגיב ב-YouTube עם הקוד שלך. זה יעזור לכולם!