יצירת רכיב של גלילת מדיה

סקירה כללית בסיסית של האופן שבו ניתן ליצור תצוגת גלילה אופקית רספונסיבית לטלוויזיות, לטלפונים, למחשבים וכו'.

בפוסט הזה אני רוצה לשתף חשיבה על דרכים ליצירת גלילה אופקית שמתאימות במיוחד לאינטרנט, עם יכולת תגובה מינימלית, ועם גישה גמישה בדפדפנים ובפלטפורמות שונות (כמו טלוויזיות!). כדאי לנסות את demo.

הדגמה

אם אתם מעדיפים סרטון, הנה גרסה של 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>. טקסט חלופי למדיה בגלילה היא הזדמנות לחוויית משתמש שעוזרת להוסיף הקשר נוסף לתמונה הממוזערת, או טקסט חלופי אם התמונה לא נטענה, או שהוא מספק למשתמשים ממשק משתמש קולי מסתמכים על טכנולוגיה מסייעת כמו קורא מסך. קבלת מידע נוסף במשחק Five Gold כללים למקש Alt תואם text.

המאפיין loading מקבל את מילת המפתח lazy כדי לסמן את התמונה הזו צריך לאחזר את המקור רק כאשר התמונה נמצאת בתוך אזור התצוגה. סוג הפריט יכול להיות ממש נחמד לרשימות גדולות, כי משתמשים יורידו רק תמונות של פריטים גוללים לתצוגה.

תמיכה בהעדפת ערכת הצבעים של המשתמש

שימוש ב-color-scheme כתג <meta> כדי לאותת לדפדפן שהדף שלך רוצה גם את הסגנון הבהיר וגם את העיצוב הכהה שמסופק של סוכן המשתמש. זהו מצב כהה בחינם או למצב בהיר, בהתאם לאופן שבו מסתכלים על זה:

<meta name="color-scheme" content="dark light">

המטא תג מספק את האות המוקדם ביותר שאפשר, לכן הדפדפן הם יכולים לבחור צבע ברירת מחדל כהה לקנבסים אם יש למשתמש העדפה לעיצוב כהה. פירוש הדבר שמעברים בין דפים באתר לא יהבהבו דף לבן בין טעינות. עיצוב כהה חלק בין טעינות, הרבה יותר יפה עיניים.

מידע נוסף מתומס סטיינר זמין בכתובת https://web.dev/color-scheme/.

הוסף תוכן

בהינתן מבנה התוכן של ul > li > a > figure > picture > img שלמעלה, המשימה הבאה היא להוסיף תמונות וכותרות שניתן לגלול בהן. ארזתי את ההדגמה תמונות placeholder סטטיות וטקסט, אבל אל תהססו להשתמש בהם מקור נתונים מועדף.

הוספת סגנון באמצעות CSS

עכשיו הגיע הזמן של שירות ה-CSS לקחת את רשימת התוכן הגנרית הזו ולהפוך אותה חוויה אישית. Netflix, חנויות האפליקציות ואתרים רבים נוספים משתמשים בפורמט אופקי כדי לארוז את אזור התצוגה בקטגוריות ובאפשרויות.

יצירת פריסת הגלילה

חשוב להימנע מחיתוך תוכן בפריסות או מהסתמכות על טקסט של חיתוך עם שלוש נקודות. בהרבה תוכניות טלוויזיה מופיעים גלילות במדיה בדיוק כמו אבל במקרים רבים מדי מדובר בתוכן שחוזר על עצמו. הפריסה הזו לא אמיתית! הוא גם מאפשר לתוכן המדיה לשנות את גודל העמודה וליצור פריסה אחת מספיק גמיש כדי להתמודד עם הרבה שילובים מעניינים.

2
השורות שמוצגות בגלילה. לאחת מהן אין שלוש נקודות, כלומר היא גבוהה יותר
השם קריא במלואו. הספר השני קצר יותר והרבה פריטים לא מוצגים
שלוש נקודות.

המאגר מאפשר לשנות את גודל העמודה על ידי ציון גודל ברירת המחדל כ- מאפיין מותאם אישית. פריסת הרשת הזו נקבעה על גודל העמודות, ניהול של הריווח והכיוון בלבד:

.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> כדי לאפשר גלילה וניווט באמצעות המקלדת דרך הרשימה שלו, אז לכל רכיב צאצא ישיר של <li> הוסר ::marker שלו באמצעות תצוגה מסוג חדש של 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 ואילך!). צפייה כאן לקצת יותר בהיסטוריה, אבל בגרסה הקצרה לא תמיד הובאו בחשבון המרווח הפנימי בתצוגת גלילה.

א&#39;
מודגשת בצד השורה האחרונה של הפריט ברשימה, ומוצגת
למרווח פנימי ולרכיב יש רוחב זהה לזה של יצירת היישור הרצוי.

כדי להערים על דפדפנים כך שיכניסו את המרווח הפנימי בסוף סרגל הגלילה, לטרגט לפי המספר האחרון בכל רשימה ולצרף פסאודו רכיב רמת המרווח הפנימי הרצויה.

.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);
  }
}

שימוש בתכונות לוגיות מאפשר לגלילה במדיה לעבוד בכל מצב כתיבה וכיוון המסמך.

הצמדה לגלילה

מאגר גלילה עם אפשרויות נוספות יכול להפוך לאזור תצוגה מוצמד עם שורה אחת של 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;
  }
}

מיקוד

ההשראה לרכיב הזה מגיעה מהפופולריות העצומה שלו בטלוויזיות, ב-App Store ועוד. בהרבה פלטפורמות של משחקי וידאו משתמשים בגלילה של מדיה כמו הפריסה הזו של מסך הבית. הפוקוס הוא חוויית משתמש ענקית של הרגע הזה, ולא רק תוספת קטנה. נניח שאתם משתמשים בגלילת המדיה הזו מתוך על הספה עם שלט רחוק, הוסיפו לאינטראקציה הזו כמה שיפורים קטנים:

.horizontal-media-scroller a {
  outline-offset: 12px;

  &:focus {
    outline-offset: 7px;
  }

  @media (prefers-reduced-motion: no-preference) {
    & {
      transition: outline-offset .25s ease;
    }
  }
}

כך הסגנון של מתאר המיקוד 7px רחוק מהתיבה, וזה נחמד המרחב המשותף. אם למשתמש אין העדפות תנועה לגבי צמצום התנועה, ההיסט עובר, ומספק תנועה עדינה לאירוע המיקוד.

אינדקס נסיעה

משתמשים בגיימפאד ובמקלדת צריכים תשומת לב מיוחדת ברשימות הארוכות האלה תוכן ואפשרויות גלילה. הדפוס המשותף לפתרון הבעיה נקרא roving Index זה כאשר מאגר פריטים מתמקד במקלדת, אבל רק ילד אחד יכול לשמור את המיקוד בכל פעם. זהו פריט שניתן להתמקד בו בכל פעם, והוא נועד לאפשר עקיפה של רשימת הפריטים שעלולה להיות ארוכה, במקום לחיצה על 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 נמצא מאחורי דגל ב-Firefox, אבל זמין בדפדפני Chromium או בממירים. מאז פריסת הרשת של גלילת המדיה מציינת רק כיוון וריווח, וניתן לשנות את הגודל שינוי בתוך שאילתת מדיה שבודקת את התמיכה ביחס גובה-רוחב. שיפור הדרגתי בעוד כמה גלילות מדיה דינמיות.

א&#39;
מוצגת בתיבה ביחס גובה-רוחב של 4:4 לצד יחסי העיצוב האחרים המשמשים: 16:9
ו-4:3

@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. באמצעות תחביר הסידור של הטיוטה, כל תמונה משנה את יחס הגובה-רוחב שלו בהתאם לשורה הראשונה, השנייה או השלישית. התחביר של Nest מאפשר גם להגדיר התאמות של אזור התצוגה, ממש עם הלוגיקה השנייה של מידות.

בזכות שירות CSS זה, התכונה זמינה ביותר מנועי דפדפן, אבל הפריסה שלהם תהיה מושכת יותר לעין.

העדפה לנתונים מופחתת

השיטה הבאה זמינה רק מאחורי דגל ב- Canary, רציתי לשתף אתכם איך אוכל לחסוך זמן משמעותי של טעינת דפים בכמה שורות של CSS. שאילתת המדיה prefers-reduced-data מאת ברמה 5 אפשר לשאול אם המכשיר נמצא כל מצב של צמצום נתונים, כמו מצב חוסך הנתונים (data Saver). אם כן, אוכל לשנות את מסמך, ובמקרה זה, להסתיר את התמונות.

ALT_TEXT_HERE

figure {
  @media (prefers-reduced-data: reduce) {
    & {
      min-inline-size: var(--size);

      & > picture {
        display: none;
      }
    }
  }
}

עדיין אפשר לנווט בתוכן, אבל בלי העלות של התמונות הכבדות ההורדה הושלמה. הנה האתר לפני ההוספה של שירות ה-CSS של prefers-reduced-data:

(7 בקשות, 100kb של משאבים ב-131 אלפיות השנייה)

ALT_TEXT_HERE

אלה ביצועי האתר לאחר הוספת שירות ה-CSS של prefers-reduced-data:

ALT_TEXT_HERE

(71 בקשות, 1.2MB של משאבים בגרסאות 1.07 שניות)

64 בקשות פחות, כלומר יהיו בערך 60 תמונות באזור התצוגה (בדיקות שבוצעו בתצוגת מסך רחב) בכרטיסייה הזו בדפדפן, עלייה של כ-80% מטעינת הדפים, וגם 10% מהנתונים שמועברים דרך החוט. שירות CSS חזק למדי.

סיכום

עכשיו אתה יודע איך עשיתי את זה, איך היית?! 🙂

בואו לגוון את הגישות שלנו ונלמד את כל הדרכים לבניית אתרים באינטרנט. יוצרים Codepen או מארחים הדגמה משלכם, שולחים לי הודעה ב-Twitter ואני אוסיף אותו הקטע 'רמיקסים' של הקהילה בהמשך.

מקור

רמיקסים קהילתיים

אין כאן שום דבר עדיין לראות!