סקירה כללית בסיסית של תהליך היצירה של רכיב כרטיסיות שדומה לזה שנמצא באפליקציות ל-iOS ול-Android.
בפוסט הזה אני רוצה לשתף חשיבה לגבי פיתוח רכיב של כרטיסיות לאינטרנט שהוא רספונסיבי, תומך בסוגי קלט שונים במכשירים שונים ופועל בכל הדפדפנים. אפשר לנסות את ההדגמה.
אם אתם מעדיפים סרטון, הנה גרסה של YouTube לפוסט:
סקירה כללית
כרטיסיות הן רכיב נפוץ במערכות עיצוב, אבל הן יכולות להיות בצורות רבות
הטפסים. בהתחלה היו כרטיסיות לשולחן העבודה שמבוססות על רכיב <frame>
, ועכשיו יש לנו
רכיבים ניידים דמויי חמאה שמכילים אנימציה לתוכן על סמך תכונות פיזיקה.
כולן מנסות את אותו הדבר: לחסוך במקום.
כיום, חוויית המשתמש בכרטיסיות היא חלק חיוני מהניווט באמצעות לחצנים הצגה או הסתרה של התוכן במסגרת התצוגה. הרבה סוגים שונים אזורי תוכן חולקים את אותו שטח, אבל הם מוצגים באופן מותנה בהתאם נבחר בסרגל הניווט.
טקטיקה באינטרנט
בסך הכול, לדעתי קל מאוד לבנות את הרכיב הזה כמה תכונות קריטיות של פלטפורמת האינטרנט:
scroll-snap-points
לאינטראקציות אלגנטיות עם החלקה ומקלדת מיקומים מתאימים של עצירות גלילה- קישורי עומק דרך גיבובים של כתובות URL בשביל תמיכה בעיגון ושיתוף של גלילה המטופלות בדף
- תמיכה בקורא מסך עם תגי עיצוב של רכיבי
<a>
ו-id="#hash"
prefers-reduced-motion
להפעלת מעברים בין עמעום הדרגתי ומיידי גלילה בדף- תכונת האינטרנט
@scroll-timeline
בטיוטה ליצירת קו תחתון באופן דינמי שינוי הצבע של הכרטיסייה שנבחרה
קוד ה-HTML
בעיקרון, כאן מדובר על: לוחצים על קישור, שכתובת ה-URL תייצג את במצב הדף, ולראות את אזור התוכן מתעדכן בזמן שהדפדפן גולל אל תואם לרכיב.
יש בו כמה חברים של תוכן מבני: קישורים ו-:target
. רביעי
נדרשת רשימת קישורים, ו-<nav>
מתאים במיוחד ורשימה של <article>
רכיבים מסוימים, ש-<section>
מתאים להם. כל גיבוב של קישור יתאים לקטע,
לאפשר לדפדפן לגלול דברים באמצעות עיגון.
לדוגמה, לחיצה על קישור מתמקדת באופן אוטומטי במאמר בנושא :target
Chrome 89, ללא צורך ב-JS. לאחר מכן המשתמש יכול לגלול את תוכן הכתבה עם
של מכשיר הקלט שלהם, כמו תמיד. זהו תוכן משלים, כפי שמצוין
תגי עיצוב.
השתמשתי בתגי העיצוב הבאים כדי לארגן את הכרטיסיות:
<snap-tabs>
<header>
<nav>
<a></a>
<a></a>
<a></a>
<a></a>
</nav>
</header>
<section>
<article></article>
<article></article>
<article></article>
<article></article>
</section>
</snap-tabs>
יש לי אפשרות ליצור חיבורים בין הרכיבים <a>
ו-<article>
עם
href
ו-id
נכסים כמו זה:
<snap-tabs>
<header>
<nav>
<a href="#responsive"></a>
<a href="#accessible"></a>
<a href="#overscroll"></a>
<a href="#more"></a>
</nav>
</header>
<section>
<article id="responsive"></article>
<article id="accessible"></article>
<article id="overscroll"></article>
<article id="more"></article>
</section>
</snap-tabs>
בשלב הבא מילאתי את המאמרים בכמויות שונות של lorem, ואת הקישורים ובאורך שונה עם קבוצת כותרות של תמונות. עם תוכן שאפשר לעבוד איתו, אנחנו יכולים להתחיל הפריסה שלו.
פריסות גלילה
יש 3 סוגים שונים של אזורי גלילה ברכיב הזה:
- הניווט (ורוד) הוא אופקי ניתן לגלילה
- אזור התוכן (כחול) הוא אופקי ניתן לגלילה
- כל פריט במאמר (ירוק) מופיע במאונך ניתן לגלול.
הגלילה כוללת 2 סוגים שונים של רכיבים:
- חלון
תיבה עם מימדים מוגדרים בעליoverflow
סגנון הנכס. - משטח גדול במיוחד
בפריסה הזו אלו המאגרים של הרשימה: nav קישורים, מאמרי מקטעים ותוכן מאמרים.
פריסה של <snap-tabs>
הפריסה ברמה העליונה שבחרתי הייתה גמישה (Flexbox). הגדרתי את הכיוון ל-
column
, כלומר הכותרת והקטע מסודרים אנכית. זאת הפעם הראשונה
בחלון הגלילה, והוא מסתיר את כל מה שמופיע כשאפשרויות נוספות מוסתרות. הכותרת ו
בקרוב יתמקדו בגלילת יתר, כתחומים נפרדים.
<snap-tabs> <header></header> <section></section> </snap-tabs>
snap-tabs { display: flex; flex-direction: column; /* establish primary containing box */ overflow: hidden; position: relative; & > section { /* be pushy about consuming all space */ block-size: 100%; } & > header { /* defend againstneeding 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }
מצביעים בחזרה לתרשים הצבעוני של 3 גלילות:
<header>
מוכן עכשיו להיות (ורוד) מאגר גלילה.<section>
מוכנה להיות גלילה (כחול) מאגר תגים.
הפריימים שהדגשתי למטה עם VisBug עוזר לנו לראות את החלונות נוצרו מאגרי גלילה.
פריסת <header>
כרטיסיות
הפריסה הבאה היא כמעט זהה: אני משתמש בגמיש כדי ליצור סדר אנכי.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
ה-.snap-indicator
צריך לעבור לרוחב עם קבוצת הקישורים, וכן
פריסת הכותרת הזאת עוזרת להגדיר את השלב הזה. אין כאן רכיבים ממוקמים בדיוק!
לאחר מכן, סגנונות הגלילה. מסתבר שאנחנו יכולים לשתף את סגנונות הגלילה
בין שני אזורי הגלילה האופקיים (כותרת וקטע), אז השתמשתי
בכיתה, .scroll-snap-x
.
.scroll-snap-x {
/* browser decide if x is ok to scroll and show bars on, y hidden */
overflow: auto hidden;
/* prevent scroll chaining on x scroll */
overscroll-behavior-x: contain;
/* scrolling should snap children on x */
scroll-snap-type: x mandatory;
@media (hover: none) {
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
}
}
כל אחד מהצרכים צריך גלישה על ציר ה-X, גלילה למלכודת גלילה מעבר לקצה, מוסתר סרגלי גלילה למכשירי מגע ולבסוף גלילה לנעילת תוכן אזורי ההצגה של המודעות. סדר הכרטיסיות במקלדת נגיש וכל מדריך לאינטראקציות להתמקד באופן טבעי. גלילה בקונטיינרים של גלילה מהירה מקבלים גם סגנון קרוסלה נחמד מהמקלדת.
הפריסה של כותרת הכרטיסיות <nav>
קישורי הניווט צריכים להיות מסודרים בקו, ללא מעברי שורה במרכז, וכל פריט קישור צריך להיצמד למאגר של תמונת הגלילה. Swift עובדים על שירות ה-CSS לשנת 2021!
<nav> <a></a> <a></a> <a></a> <a></a> </nav>
nav { display: flex; & a { scroll-snap-align: start; display: inline-flex; align-items: center; white-space: nowrap; } }
כל קישור מתאים לסגנון ולגודל שלו, לכן צריך לציין רק בפריסת הניווט את הכיוון והזרימה. מידות רוחב ייחודיות בפריטי ניווט מבצעים את המעבר בין כרטיסיות כי המחוון מתאים את רוחבו ליעד החדש. בהתאם לכמות שקיימים כאן, הדפדפן יציג סרגל גלילה או לא.
פריסת <section>
כרטיסיות
הקטע הזה הוא פריט גמישה והוא צריך להיות הצרכן הדומיננטי של המרחב. הוא
צריך גם ליצור עמודות שבהן המאמרים ימוקמו. שוב, מהר
עובדים בשביל CSS 2021! הרכיב block-size: 100%
נמתח כדי למלא את
כמה שיותר הורה, ואז לפריסה משלו הוא יוצר סדרה של
עמודות שהרוחב שלהן הוא 100%
מהרוחב של תבנית ההורה. אחוזים פועלים כאן מצוין
כי כתבנו מגבלות חזקות על ההורה.
<section> <article></article> <article></article> <article></article> <article></article> </section>
section { block-size: 100%; display: grid; grid-auto-flow: column; grid-auto-columns: 100%; }
זה כאילו אנחנו אומרים "הרחב אנכית ככל האפשר, באופן נדחף"
(חשוב לזכור את הכותרת שהגדרנו בתור flex-shrink: 0
: היא הגנה מפני
דחיפת הרחבה), שמגדירה את גובה השורה של קבוצה של עמודות בגובה מלא.
הסגנון auto-flow
מורה לרשת תמיד לפרוס את הילדים לרוחב
שורה חדשה, בלי גלישת טקסט, בדיוק מה שאנחנו רוצים; כדי לגלוש בחלון ההורה.
לפעמים קשה לי לסובב את הראש! רכיב הקטע הזה שהכניסו לקופסה, אבל יצרו גם סדרה של קופסאות. אני מקווה שהרכיבים החזותיים אבל ההסברים עוזרים.
פריסת <article>
כרטיסיות
למשתמש צריכה להיות אפשרות לגלול את תוכן המאמר, וסרגלי הגלילה צריכים מופיעים רק אם יש גלישה. רכיבי המאמר האלה המיקום. הם מוגדרים בו-זמנית כהורה שגולל וגם כילד שגולל. הדפדפן באמת מטפל באינטראקציות מורכבות של מגע, עכבר ומקלדת עבורנו כאן.
<article> <h2></h2> <p></p> <p></p> <h2></h2> <p></p> <p></p> ... </article>
article { scroll-snap-align: start; overflow-y: auto; overscroll-behavior-y: contain; }
בחרתי לצלם את הכתבות בגלילה הראשית של ההורה. אני ממש אוהב האופן שבו פריטי קישור הניווט ורכיבי הכתבה מוצמדים לשעון של מאגרי הגלילה המתאימים. נראה ומרגיש הרמוניה קשר גומלין.
המאמר הוא צאצא מסוג 'רשת', והגודל שלו נקבע מראש כאזור התצוגה. שאנחנו רוצים לספק גלילה בחוויית המשתמש. המשמעות היא שאין לי צורך בגובה או רוחב כאן, אני רק צריך להגדיר איך היא גולשת. אני מגדיר את overflow-y למצב אוטומטי, ואז גם מלכודות את האינטראקציות בגלילה באמצעות ההתנהגות השימושית של גלילת יתר לנכס.
סיכום של 3 אזורי גלילה
למטה בחרתי בהגדרות המערכת "להציג תמיד פסי גלילה". לדעתי פעמיים חשוב מאוד שהפריסה תפעל גם כשההגדרה הזאת מופעלת, כי הוא שאוכל לבדוק את הפריסה ואת תזמור הגלילה.
אני חושב שלראות את המרזב של סרגל הגלילה ברכיב הזה עוזר להראות בבירור איפה מהם אזורי הגלילה, הכיוון שבו הם תומכים וכיצד הם יוצרים איתם אינטראקציה שתי רשתות נוירונים זו מול זו. כדאי לחשוב איך כל אחת מהמסגרות של חלונות הגלילה האלה גמישה או לפריסה.
כלי הפיתוח יכולים לעזור לנו להמחיש את הדברים הבאים:
פריסות הגלילה שלמות: קישור, קישור עומק ומקלדת נגיש. בסיס חזק לשיפורי חוויית המשתמש, לסגנון ולחוויה טובה.
תכונה בולטת
ילדים מוצמדים נשמרים על המיקום הנעול במהלך שינוי הגודל. כלומר JavaScript לא יצטרך להציג שום דבר בתצוגה מסתובבת במכשיר או בדפדפן לשנות את הגודל. רוצה לנסות את זה במכשיר של כלי הפיתוח ל-Chromium? מצב לפי בחירה במצב שאינו רספונסיבי, ולאחר מכן שינוי הגודל של מסגרת המכשיר. שימו לב שהאלמנט נשאר גלוי וננעל עם התוכן שלו. זה היה מאז ש-Chromium עדכן את ההטמעה בהתאם למפרט. הנה פוסט בבלוג שעוסק בו.
Animation
מטרת האנימציה הזו היא לקשר באופן ברור בין האינטראקציות עם ממשק המשתמש משוב. זה עוזר להנחות או לעזור למשתמש להגיע אל (בתקווה) לגלות את כל התוכן באופן חלק. אני אוסיף תנועה מתוך מטרה באופן מותנה. המשתמשים יכולים עכשיו לציין את התנועה שלהם העדפות במערכת ההפעלה שלהם, ואני נהנית מאוד להשיב להעדפות שלהם בממשקים שלי.
אני אקשר קו תחתון של כרטיסייה למיקום הגלילה של המאמר. הצמדה היא לא
ליישור יפה בלבד, הוא גם מקבע את ההתחלה והסוף של האנימציה.
הפעולה הזו שומרת על <nav>
, שפועל כמו
מיני-מפה, שמקושר לתוכן.
אנחנו נבדוק את העדפת התנועה של המשתמש גם ב-CSS וגם ב-JS. יש
יש כמה מקומות מעולים להתחשבות!
התנהגות הגלילה
יש הזדמנות לשפר את התנהגות התנועה של :target
וגם
element.scrollIntoView()
. כברירת מחדל, מיידי. הדפדפן פשוט מגדיר את
מעבר למצב הגלילה. מה אם אנחנו רוצים לעבור למיקום הגלילה הזה,
במקום להמצמץ לשם?
@media (prefers-reduced-motion: no-preference) {
.scroll-snap-x {
scroll-behavior: smooth;
}
}
מכיוון שאנחנו מכניסים כאן תנועה, ותנועה שהמשתמש לא שולט בה (למשל גלילה), אנחנו מחילים את הסגנון הזה רק אם למשתמש אין העדפה את מערכת ההפעלה שלהם סביב תנועה מופחתת. באופן הזה, אנחנו משיקים רק את הגלילה תנועה לאנשים שמקובלים איתם.
אינדיקטור של כרטיסיות
מטרת האנימציה הזו היא לעזור לשייך את האינדיקטור למצב
של התוכן. החלטתי לצבוע סגנונות עמעום של border-bottom
למשתמשים
שמעדיפים תנועה מופחתת ואנימציה של החלקה מקושרת + עמעום צבעים
למשתמשים שמביעים עניין בתנועה.
בכלי הפיתוח ל-Chromium, אני יכול להחליף את מצב ההעדפה ולהדגים את השניים סגנונות מעבר שונים. נהניתי מאוד לבנות את זה.
@media (prefers-reduced-motion: reduce) {
snap-tabs > header a {
border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
transition: color .7s ease, border-color .5s ease;
&:is(:target,:active,[active]) {
color: var(--text-active-color);
border-block-end-color: hsl(var(--accent));
}
}
snap-tabs .snap-indicator {
visibility: hidden;
}
}
אני מסתירה את .snap-indicator
כשהמשתמש מעדיפים תנועה מופחתת, כי אני לא רוצה לעשות זאת
עוד יותר צריכים אותו. לאחר מכן אני מחליף אותו ב-border-block-end
סגנונות
transition
. כמו כן, ניתן לשים לב באינטראקציות של הכרטיסיות שפריט הניווט הפעיל לא
יש רק הדגשה של קו תחתון למותג, אבל צבע הטקסט גם כהה יותר.
לרכיב פעיל יש ניגודיות גבוהה יותר של צבע הטקסט והדגשה בהירה של טקסט תחתון.
רק עוד כמה שורות של CSS יגרמו לאנשים לראות אתכם (במשמעות של ואנחנו מכבדים היטב את העדפות התנועה שלהם). אני מת על זה.
@scroll-timeline
בקטע שלמעלה, הראיתי איך מטפלים בעמעום הדרגתי בתנועה המופחתת. ובסעיף הזה אראה לכם איך קישרתי את האינדיקטור באזור הגלילה ביחד. הנה כמה דברים ניסיוניים ומהנים שצפויים בהמשך. אני מקווה בהתרגשות כמוני.
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
);
אני בודק תחילה את העדפת התנועה של המשתמש מ-JavaScript. אם התוצאה של
הערך הוא false
, כלומר המשתמש מעדיפים תנועה מופחתת, ואז לא נריץ שום תנועה
של האפקטים של התנועה לקישור הגלילה.
if (motionOK) {
// motion based animation code
}
נכון לזמן כתיבת ההודעה הזו, הדפדפן תומך ב
@scroll-timeline
הוא לא. אלה
מפרטי טיוטה שכוללים רק
הטמעות ניסיוניות. אבל יש לו polyfill, ואני משתמש בו
.
ScrollTimeline
שירות CSS ו-JavaScript יכולים ליצור לוחות זמנים לגלילה, אבל הסכמתי JavaScript, כדי שאוכל להשתמש במדידות של רכיבים פעילים באנימציה.
const sectionScrollTimeline = new ScrollTimeline({
scrollSource: tabsection, // snap-tabs > section
orientation: 'inline', // scroll in the direction letters flow
fill: 'both', // bi-directional linking
});
אני רוצה שפריט אחד יעקוב אחר מיקום הגלילה של אחר, ועל ידי יצירת
ScrollTimeline
אני מגדיר את הנהג שאליו מוביל קישור הגלילה, scrollSource
.
בדרך כלל אנימציה באינטרנט פועלת בהתאם לסימון מסגרת זמן גלובלית, אבל
sectionScrollTimeline
בהתאמה אישית בזיכרון, אפשר לשנות את כל זה.
tabindicator.animate({
transform: ...,
width: ...,
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
לפני שנעבור לתמונות המפתח של האנימציה, אני חושב שחשוב
לציון העוקב אחרי הגלילה, tabindicator
, תוצג אנימציה על סמך
בציר זמן מותאם אישית, גלילה בקטע שלנו. הקישור הושלם, אבל
חסר המרכיב הסופי, נקודות קיצוניות להנפשה, שנקרא גם
תמונות מפתח.
תמונות מפתח דינמיות
יש שירות CSS הצהרתי ועוצמתי מאוד שבו ניתן להנפיש
@scroll-timeline
, אבל האנימציה שבחרתי הייתה דינמית מדי. אין
דרך לעבור בין רוחב של auto
, ואין דרך ליצור באופן דינמי
מספר תמונות מפתח שמבוססות על האורך של הילדים.
אבל JavaScript יודע איך לקבל את המידע הזה, ולכן נחזור על לילדים בעצמנו ולקחת את הערכים המחושבים בזמן ריצה:
tabindicator.animate({
transform: [...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`),
width: [...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
לכל tabnavitem
, מסירים את המיקום offsetLeft
ומחזירים מחרוזת
שמשתמש בו כערך translateX
. ייווצרו 4 תמונות מפתח של טרנספורמציה
אנימציה. כך גם לגבי רוחב, כל אחד שואלים מה הרוחב הדינמי שלו
ולאחר מכן הוא משמש כערך של תמונת מפתח.
הנה פלט לדוגמה, על סמך הגופנים והעדפות הדפדפן שלי:
תמונות מפתח של TranslateX:
[...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`)
// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]
תמונות מפתח ברוחב:
[...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]
לסיכום האסטרטגיה, אינדיקטור הכרטיסייה יכלול מעכשיו אנימציה ב-4 תמונות מפתח בהתאם למיקום ההצמדה של גלילת הקטעים. נקודות הצמדה ליצור קו ברור בין תמונות המפתח ולהוסיף תחושה מסונכרנת של האנימציה.
המשתמש מפעיל את האנימציה בעזרת האינטראקציה שלו, רואה את הרוחב המיקום של המדד משתנה מקטע אחד לקטע הבא, מעקב בצורה מושלמת עם הגלילה.
אולי לא שמת לב, אבל אני גאה מאוד בשינוי הצבע בתור פריט הניווט המודגש נבחר.
האפשרות האפורה הבהירה יותר שלא נבחרה תופיע בדחיפה עוד יותר כשהלוגו המודגש יש ניגודיות גבוהה יותר בפריט. מקובל לשנות צבע של טקסט, למשל כשמעבירים את העכבר מעל וכשבוחרים באפשרות הזו, זה השלב הבא שבו ניתן להעביר את הצבע בזמן הגלילה, מסונכרן עם האינדיקטור של הקו התחתון.
כך עשיתי:
tabnavitems.forEach(navitem => {
navitem.animate({
color: [...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
});
כל קישור לניווט בכרטיסייה זקוק לאנימציה החדשה והצבעונית הזו, העוקבת אחרי אותה גלילה כאינדיקטור של קו תחתון. אני משתמש באותו ציר זמן כמו קודם: התפקיד שלו הוא לחולל סמן בזמן הגלילה, נוכל להשתמש בסימון הזה בכל סוג האנימציה שאנחנו רוצים. כמו קודם, אני יוצר 4 תמונות מפתח בלולאה ומחזיר צבעים.
[...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
// results in 4 array items, which represent 4 keyframe states
// [
"var(--text-active-color)",
"var(--text-color)",
"var(--text-color)",
"var(--text-color)",
]
תמונת המפתח עם הצבע var(--text-active-color)
מדגישה את הקישור, וגם
אחרת הוא צבע טקסט סטנדרטי. הלולאה המוצבת שם הופכת אותה
פשוטה, כיוון שהלולאה החיצונית היא כל פריט ניווט, והלולאה הפנימית
תמונות המפתח האישיות של navitem. אני בודק אם רכיב הלולאה החיצוני זהה
את הלולאה הפנימית, ולהשתמש בה כדי לדעת מתי היא מסומנת.
נהניתי מאוד לכתוב את זה. כל כך הרבה.
שיפורי JavaScript נוספים
כדאי לזכור שהעיקרון של מה שמוצג לך כאן פועל בלי JavaScript. עם זאת, בואו נראה איך נוכל לשפר אותו כש-JS זמינים.
קישורי עומק
קישורי עומק הם יותר כמו מונח לנייד, אבל לדעתי הכוונה של קישור העומק היא
כאן יש כרטיסיות שמאפשרות לשתף כתובת URL ישירות לתוכן של כרטיסייה.
הדפדפן ינווט בדף למזהה שתואם בגיבוב של כתובת ה-URL. מצאתי
ה-handler הזה של onload
ביצע את ההשפעה בכל הפלטפורמות.
window.onload = () => {
if (location.hash) {
tabsection.scrollLeft = document
.querySelector(location.hash)
.offsetLeft;
}
}
סנכרון סוף גלילה
המשתמשים שלנו לא תמיד לוחצים או משתמשים במקלדת, לפעמים הם פשוט לגלול בחינם, כפי שאמורה להיות להם. כשהגלילה של הקטעים נעצרת בגלילה, בכל מקום שבו הוא נוחת, צריכה להיות התאמה בסרגל הניווט העליון.
כך אני מחכה לסוף הגלילה:
js
tabsection.addEventListener('scroll', () => {
clearTimeout(tabsection.scrollEndTimer);
tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100);
});
בכל פעם שמתבצעת גלילה של הקטעים, נקה את הזמן הקצוב לתפוגה של קטע אם קיים, ולהתחיל תהליך חדש. כשהגלילה של קטעים נפסקת, לא מנקים את הזמן הקצוב לתפוגה. ונדליקים 100 אלפיות השנייה אחרי מנוחה. כשהוא מופעל, הפונקציה קריאה שמבקשת במקום שבו המשתמש עצר.
const determineActiveTabSection = () => {
const i = tabsection.scrollLeft / tabsection.clientWidth;
const matchingNavItem = tabnavitems[i];
matchingNavItem && setActiveTab(matchingNavItem);
};
בהנחה שהגלילה אותרה, חלוקה של מיקום הגלילה הנוכחי מהרוחב של אזור הגלילה צריך להציג מספר שלם ולא מספר עשרוני. לאחר מכן אני מנסה תאחזר פריט ניווט מהמטמון שלנו דרך האינדקס המחושב, ואם הוא ימצא משהו, אני שולח את ההתאמה למצב פעיל.
const setActiveTab = tabbtn => {
tabnav
.querySelector(':scope a[active]')
.removeAttribute('active');
tabbtn.setAttribute('active', '');
tabbtn.scrollIntoView();
};
כדי להגדיר את הכרטיסייה הפעילה, קודם צריך למחוק את כל הכרטיסיות הפעילות, ואז
פריט הניווט הנכנס הוא מאפיין המצב הפעיל. השיחה אל scrollIntoView()
שיש לה אינטראקציה מהנה עם CSS, שכדאי להכיר.
.scroll-snap-x {
overflow: auto hidden;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
ב-CSS של הכלי להצמדה אופקית של גלילה אופקית,
הציב שאילתת מדיה שרלוונטית
גלילה smooth
אם המשתמש סביל לתנועה. JavaScript יכול ליצור
קריאות לגלילה כדי להציג רכיבים, ושירות CSS יכול לנהל את חוויית המשתמש באופן הצהרתי.
ממש התאמת הקטנה שהם יוצרים לפעמים.
סיכום
עכשיו אתה יודע איך עשיתי את זה, איך היית?! זה כיף גדול ארכיטקטורת רכיבים. מי יקבל את הגרסה הראשונה עם מיקומי מודעות מסגרת אהובה? 🙂
בואו לגוון את הגישות שלנו ונלמד את כל הדרכים לבניית אתרים באינטרנט. יצירת תקלה, שליחת ציוץ לי של הגרסה שלכם, ואני אוסיף אותה לרמיקסים של הקהילה שבהמשך.
רמיקסים קהילתיים
- @devnook, @rob_dodson ו-@DasSurma עם רכיבי אינטרנט: article.
- @jhvanderschee עם לחצנים: Codepen.