סקירה כללית בסיסית על יצירת תצוגת גלילה אופקית רספונסיבית לטלוויזיות, לטלפונים, למחשבים וכו'.
בפוסט הזה אני רוצה לשתף את החשיבה שלי לגבי דרכים ליצור חוויית גלילה אופקית באינטרנט שמינימלית, רספונסיבית, נגישה ופועלת בכל הדפדפנים והפלטפורמות (כמו טלוויזיות!). כדאי לנסות את ההדגמה.
אם אתם מעדיפים סרטון, הנה גרסה של הפוסט הזה ב-YouTube:
סקירה כללית
אנחנו נבנה פריסה עם גלילה אופקית שמיועדת לאירוח תמונות ממוזערות של מדיה או מוצרים. הרכיב מתחיל כרשימה פשוטה של <ul>
, אבל בעזרת CSS הוא הופך לחוויית גלילה נעימה וחלקה, שבה מוצגות תמונות שמתמקמות בתוך רשת. JavaScript מתווסף כדי לאפשר אינטראקציות עם מדד נע, וכך לעזור למשתמשים במקלדת לדלג על סריקה של יותר מ-100 פריטים.
בנוסף, שאילתת מדיה ניסיונית, prefers-reduced-data
, משמשת כדי להפוך את גלילה של מדיה לחוויית גלילה קלה של כותרות.
מתחילים עם תג עיצוב נגיש
גלילה של מדיה מורכבת רק מכמה רכיבים מרכזיים, רשימה עם פריטים. רשימה, בצורתה הפשוטה ביותר, יכולה לעבור לכל רחבי העולם ולהיות נגישה לכולם. משתמש שמגיע לדף הזה יכול לעיין ברשימה וללחוץ על קישור כדי להציג פריט. זהו הבסיס הנגיש שלנו.
שליחת רשימה עם רכיב <ul>
:
<ul class="horizontal-media-scroller">
<li></li>
<li></li>
<li></li>
...
<ul>
כדי להפוך את הפריטים ברשימה לאינטראקטיביים, משתמשים באלמנט <a>
:
<li>
<a href="#">
...
</a>
</li>
משתמשים ברכיב <figure>
כדי לייצג סמנטית תמונה ואת הכותרת שלה:
<figure>
<picture>
<img alt="..." loading="lazy" src="https://picsum.photos/500/500?1">
</picture>
<figcaption>Legends</figcaption>
</figure>
שימו לב למאפיינים alt
ו-loading
ב-<img>
. טקסט חלופי לסליידר של מדיה הוא הזדמנות לשיפור חוויית המשתמש, שבעזרתו אפשר להוסיף לתמונה הממוזערת הקשר נוסף, או להשתמש בו כטקסט חלופי אם התמונה לא נטענת. הוא גם מספק ממשק משתמש קולי למשתמשים שמסתמכים על טכנולוגיה מסייעת כמו קורא מסך. חמישה כללים מוזהבים לטקסט חלופי תואם
המאפיין loading
מקבל את מילת המפתח lazy
כדי לסמן שצריך לאחזר את מקור התמונה הזה רק כשהתמונה נמצאת באזור התצוגה. האפשרות הזו יכולה להיות שימושית מאוד ברשימות גדולות, כי המשתמשים יורידו תמונות רק של פריטים שהם גוללו אליהם.
תמיכה בהעדפת ערכת הצבעים של המשתמש
משתמשים ב-color-scheme
בתור תג <meta>
כדי לאותת לדפדפן שהדף רוצה גם את הסגנונות הבהירים וגם את הסגנונות הכהים של סוכן המשתמש. זהו מצב כהה או מצב בהיר בחינם, תלוי איך מסתכלים על זה:
<meta name="color-scheme" content="dark light">
המטא תג מספק את האות המוקדם ביותר האפשרי, כך שהדפדפן יכול לבחור צבע ברירת מחדל כהה של קנבס אם למשתמש יש העדפה לעיצוב כהה. המשמעות היא שבמהלך ניווט בין דפי האתר לא יופיע רקע לבן של קנבס בין הטעינות. עיצוב כהה חלק בין עומסי עבודה, נעים יותר לעין.
מידע נוסף זמין באתר של Thomas Steiner בכתובת https://web.dev/color-scheme/.
הוסף תוכן
בהתאם למבנה התוכן של ul > li > a > figure > picture > img
שמתואר למעלה, המשימה הבאה היא להוסיף תמונות וכותרות לגלילה. הכנסתי לדמו תמונות ו-placeholders סטטיים של טקסט, אבל אתם יכולים להשתמש במקור הנתונים המועדף עליכם.
הוספת סגנון באמצעות CSS
עכשיו הגיע הזמן ש-CSS יטפל ברשימה הזו של תוכן כללי ויהפוך אותה לחוויה. Netflix, חנויות אפליקציות ואתרים ואפליקציות רבים נוספים משתמשים באזורי גלילה אופקיים כדי לארוז את אזור התצוגה בקטגוריות ובאפשרויות.
יצירת הפריסה של פס ההזזה
חשוב להימנע מקיצוץ תוכן בפריסות או משימוש בפסיק נטוי (ellipsis) כדי לקצר טקסט. במכשירי טלוויזיה רבים יש גלילות מדיה כמו זו, אבל לעיתים קרובות מדי הן משתמשות בפסיק נטוי כדי להסתיר תוכן. הפריסה הזו לא עושה זאת. בנוסף, תוכן המדיה יכול לשנות את גודל העמודה, כך שפריסה אחת יכולה להתאים למגוון שילובים מעניינים.
בעזרת הקונטיינר אפשר לשנות את גודל העמודה על ידי ציון גודל ברירת המחדל כמאפיין מותאם אישית. בפריסה הזו של הרשת יש דעה מוגדרת לגבי גודל העמודות, והיא מנהלת רק את המרווחים והכיוון:
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2); /* parent owned value for children to be relative to*/
margin: 0;
}
לאחר מכן, הרכיב <picture>
משתמש במאפיין המותאם אישית כדי ליצור את יחס הגובה-רוחב הבסיסי שלנו: תיבת:
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
& picture {
inline-size: var(--size);
block-size: var(--size);
}
}
בעזרת עוד כמה סגנונות משניים, אפשר להשלים את היסודות של פס ההזזה של התמונות והסרטונים:
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
overflow-x: auto;
overscroll-behavior-inline: contain;
& > li {
display: inline-block; /* removes the list-item bullet */
}
& picture {
inline-size: var(--size);
block-size: var(--size);
}
}
ההגדרה overflow
מגדירה את <ul>
כך שיאפשר גלילה וניווט במקלדת ברשימת הרכיבים שלו. לאחר מכן, הרכיב ::marker
של כל רכיב צאצא ישיר <li>
יוסר על ידי הקצאת סוג תצוגה חדש של inline-block
.
עם זאת, התמונות עדיין לא רספונסיביות והן יוצאות מחוץ לתיבות שבהן הן נמצאות. אפשר לשנות את הגדלים, הסגנונות של ההתאמה והגבולות, וגם להוסיף שיפוע לרקע כשהם נטענים באיטרציה:
img {
/* smash into whatever box it's in */
inline-size: 100%;
block-size: 100%;
/* don't squish but do cover the space */
object-fit: cover;
/* soften the edges */
border-radius: 1ex;
overflow: hidden;
/* if empty, show a gradient placeholder */
background-image:
linear-gradient(
to bottom,
hsl(0 0% 40%),
hsl(0 0% 20%)
);
}
מרווח פנימי לגלילה
התאמה לתוכן הדף, ושטח גלילה מקצה לקצה, הם חיוניים ליצירת רכיב הרמוני ומינימלי.
כדי ליצור פריסת גלילה מקצה לקצה שתואמת לקו העיצוב ולטיפוגרפיה שלנו, צריך להשתמש ב-padding
שתואם ל-scroll-padding
:
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
overflow-x: auto;
overscroll-behavior-inline: contain;
padding-inline: var(--gap);
scroll-padding-inline: var(--gap);
padding-block: calc(var(--gap) / 2); /* make space for scrollbar and focus outline */
}
תיקון באג של תוספת רווח לגלילה אופקית הקוד שלמעלה מראה כמה קל להוסיף רווח לקונטיינר גלילה, אבל יש בעיות תאימות לא פתורות בנושא (למרות שהבעיה תוקנה ב-Chromium מגרסה 91 ואילך). כאן תוכלו לקרוא על ההיסטוריה של הבעיה, אבל בקצרה: לא תמיד נלקח בחשבון כיסוי בזמן גלילה.
כדי לגרום לדפדפנים להוסיף את הרווח בסוף סרגל ההזזה, אטרגט את הדמות האחרונה בכל רשימה ואוסיף רכיב פסאודו שגודלו זהה לרווח הרצוי.
.horizontal-media-scroller > li:last-of-type figure {
position: relative;
&::after {
content: "";
position: absolute;
inline-size: var(--gap);
block-size: 100%;
inset-block-start: 0;
inset-inline-end: calc(var(--gap) * -1);
}
}
שימוש במאפיינים לוגיים מאפשר לפס ההזזה של המדיה לפעול בכל מצב כתיבה ובכל כיוון של המסמך.
גלילה עם נקודות עצירה (scroll snapping)
תוכלו להפוך מאגר גלילה עם גלישת-overflow למסך תצוגה עם הצמדה באמצעות שורת CSS אחת. לאחר מכן, הילדים יצטרכו לציין איך הם רוצים להתאים את עצמם למסך התצוגה הזה.
.horizontal-media-scroller {
--size: 150px;
display: grid;
grid-auto-flow: column;
gap: calc(var(--gap) / 2);
margin: 0;
overflow-x: auto;
overscroll-behavior-inline: contain;
padding-inline: var(--gap);
scroll-padding-inline: var(--gap);
padding-block-end: calc(var(--gap) / 2);
scroll-snap-type: inline mandatory;
& figure {
scroll-snap-align: start;
}
}
מיקוד
ההשראה לרכיב הזה נובעת מהפופולריות העצומה שלו בטלוויזיות, בחנויות אפליקציות ועוד. בפלטפורמות רבות של משחקי וידאו נעשה שימוש בפס גלילה של מדיה שדומה מאוד לזה, בתור הפריסה הראשית של מסך הבית. התכונה הזו היא חלק חשוב מאוד מחוויית המשתמש, ולא רק תוספת קטנה. נניח שאתם משתמשים בגלילה של המדיה מהספה באמצעות שלט רחוק. תוכלו לשפר את האינטראקציה הזו במספר דרכים קטנות:
.horizontal-media-scroller a {
outline-offset: 12px;
&:focus {
outline-offset: 7px;
}
@media (prefers-reduced-motion: no-preference) {
& {
transition: outline-offset .25s ease;
}
}
}
כך מגדירים את סגנון קווי המתאר של המיקוד 7px
הרחק מהתיבה, ומשאירים לה קצת מקום. אם למשתמש אין העדפות תנועה לגבי צמצום תנועה, מתבצע מעבר של ההיסט, וכך תנועה עדינה מועברת לאירוע המיקוד.
אינדקס נייד
משתמשים במקלדת ובג'וימפקד צריכים תשומת לב מיוחדת ברשימה הארוכה הזו של תוכן ואפשרויות לגלילה. התבנית הנפוצה לפתרון הבעיה הזו נקראת אינדקס נייד. המצב הזה מתרחש כשקונטיינר של פריטים מקבל את המיקוד במקלדת, אבל רק צאצא אחד יכול לקבל את המיקוד בכל פעם. חוויית השימוש הזו, שבה אפשר להתמקד בפריט אחד בכל פעם, נועדה לאפשר לעקוף את רשימת הפריטים הארוכה, במקום ללחוץ על Tab יותר מ-50 פעמים כדי להגיע לסוף.
יש 300 פריטים בגלילה הראשונה בדמו. אנחנו יכולים לעשות יותר מאשר לגרום להם לעבור את כולם כדי להגיע לקטע הבא.
כדי ליצור את החוויה הזו, JavaScript צריך לעקוב אחרי אירועי מקלדת ואירועי התמקדות. כדי לעזור לכם להשיג את חוויית המשתמש הזו בקלות, יצרתי ספרייה קטנה בקוד פתוח ב-npm. כך משתמשים בו ב-3 גלילות:
import {rovingIndex} from 'roving-ux';
rovingIndex({
element: someElement
});
הדגמה הזו שולחת שאילתה למסמך כדי למצוא את גלילי הגלילה, ומפעילה את הפונקציה rovingIndex()
לכל אחד מהם. מעבירים את האלמנט rovingIndex()
כדי לקבל את חוויית המעבר, כמו מאגר רשימות ובורר של שאילתות יעד, במקרה שהיעדים שבמרכז העניין הם לא צאצאים ישירים.
document.querySelectorAll('.horizontal-media-scroller')
.forEach(scroller =>
rovingIndex({
element: scroller,
target: 'a',
}))
מידע נוסף על האפקט הזה זמין בספרייה של קוד פתוח roving-ux.
Aspect-ratio
נכון למועד כתיבת הפוסט הזה, התמיכה ב-aspect-ratio
מופעלת באמצעות דגל ב-Firefox, אבל היא זמינה בדפדפני Chromium או במכשירי ממיר. מכיוון שפריסת הרשת של גלילה של מדיה מציינת רק את הכיוון והרווח, הגודל יכול להשתנות בתוך שאילתה של מדיה, שבה מתבצעת בדיקה של תמיכה ביחס גובה-רוחב.
שיפור הדרגתי של גלילות מדיה דינמיות יותר.
@supports (aspect-ratio: 1) {
.horizontal-media-scroller figure > picture {
inline-size: auto; /* for a block-size driven ratio */
aspect-ratio: 1; /* boxes by default */
@nest section:nth-child(2) & {
aspect-ratio: 16/9;
}
@nest section:nth-child(3) & {
/* double the size of the others */
block-size: calc(var(--size) * 2);
aspect-ratio: 4/3;
/* adjust size to fit more items into the viewport */
@media (width <= 480px) {
block-size: calc(var(--size) * 1.5);
}
}
}
}
אם הדפדפן תומך בסינטקס aspect-ratio
, התמונות בסרגל הגלילה של המדיה משודרגות לגודל aspect-ratio
. באמצעות תחביר ההטמעה של הטיוטה, יחס הגובה-רוחב של כל תמונה משתנה בהתאם לשורה שבה היא נמצאת – הראשונה, השנייה או השלישית. תחביר העץ מאפשר גם להגדיר התאמות קטנות של חלון התצוגה, יחד עם לוגיק הגודל האחר.
בעזרת ה-CSS הזה, מאחר שהתכונה זמינה במנועי דפדפנים נוספים, המערכת תיצור פריסה נוחה לניהול אבל מושכת יותר מבחינה ויזואלית.
העדפה לצמצום נתונים
השיטה הבאה זמינה רק אחרי הפעלת דגל ב-Canary, אבל רציתי לשתף איך הצלחתי לחסוך זמן טעינה משמעותי של דפים ושימוש משמעותי בנתונים באמצעות כמה שורות של CSS. שאילתה המדיה prefers-reduced-data
מרמה 5 מאפשרת לבדוק אם המכשיר נמצא במצב של שימוש מופחת בנתונים, כמו מצב חיסכון בנתונים. אם כן, אוכל לשנות את המסמך, ובמקרה הזה להסתיר את התמונות.
figure {
@media (prefers-reduced-data: reduce) {
& {
min-inline-size: var(--size);
& > picture {
display: none;
}
}
}
}
עדיין אפשר לנווט בתוכן, אבל בלי העלות של הורדת התמונות הכבדות. זהו האתר לפני הוספת ה-CSS של prefers-reduced-data
:
(7 בקשות, 100KB של משאבים ב-131ms)
אלה הביצועים של האתר אחרי הוספת ה-CSS של prefers-reduced-data
:
(71 בקשות, 1.2MB של משאבים ב-1.07 שניות)
64 בקשות פחות, כלומר כ-60 תמונות בחלון התצוגה (בדיקות שנערכו במסך רחב) בכרטיסייה הזו בדפדפן, שיפור של כ-80% בטעינת הדף ו-10% מהנתונים שמועברים באינטרנט. CSS חזק למדי.
סיכום
עכשיו, אחרי שסיפרתי לך איך עשיתי את זה, איך היית עושה את זה? 🙂
נרחיב את הגישות שלנו ונלמד את כל הדרכים לפיתוח באינטרנט. אתם יכולים ליצור דוגמה ב-Codepen או לארח דוגמה משלכם, לשלוח לי אותה בטוויטר ואוסיף אותה לקטע 'רמיקסים של הקהילה' שבהמשך.
מקור
רמיקסים של הקהילה
עדיין אין מה לראות כאן