יצירת רכיב של סטוריז

סקירה כללית בסיסית על יצירת חוויה דומה ל-Instagram Stories באינטרנט.

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

דמו

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

אם אתם מעדיפים סרטון, הנה גרסה של הפוסט הזה ב-YouTube:

סקירה כללית

שתי דוגמאות פופולריות לחוויית המשתמש של סטורי הן Snapchat Stories ו-Instagram Stories (בלי לדבר על Fleets). באופן כללי, סטוריז הם בדרך כלל תבנית שמתמקדת בהקשות ומתאימה לנייד בלבד, שמאפשרת לנווט בין כמה מינויים. לדוגמה, ב-Instagram, משתמשים פותחים סטוריז של חברים ומעיינים בתמונות שבהם. בדרך כלל הם עושים זאת למספר רב של חברים בו-זמנית. מקישים על הצד השמאלי של המכשיר כדי לדלג לסטורי הבא של אותו חבר או חברה. החלקה ימינה מאפשרת למשתמש לדלג לידיד אחר. רכיב סטורי דומה למדי לקרוסלה, אבל מאפשר לנווט במערך רב-מימדי במקום במערך חד-מימדי. זה כמו שיש קרוסלה בתוך כל קרוסלה. 🤯

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

בחירת הכלים המתאימים למשימה

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

CSS Grid

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

פריסת החברים

העטיפה הראשית של הרכיב .stories היא תצוגת גלילה אופקית שמותאמת במיוחד לניידים:

.stories {
  inline-size: 100vw;
  block-size: 100vh;

  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;

  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}

/* desktop constraint */
@media (hover: hover) and (min-width: 480px) {
  max-inline-size: 480px;
  max-block-size: 848px;
}
שימוש במצב מכשיר בכלי הפיתוח ל-Chrome כדי להדגיש את העמודות שנוצרו על ידי Grid

נבחן את הפריסה grid:

  • אנחנו ממלאים במפורש את אזור התצוגה בנייד באמצעות 100vh ו-100vw ומגבילים את הגודל במחשב
  • / מפריד בין התבניות של השורות והעמודות
  • auto-flow מתורגם ל-grid-auto-flow: column
  • התבנית של התנועה האוטומטית היא 100%, ובמקרה הזה היא תהיה רוחב חלון הגלילה

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

יצירת מקבצים

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

בעזרת רשת CSS אפשר להגדיר רשת של תא יחיד (כלומר ריבוע), שבו השורות והעמודות משתפות כינוי ([story]), ולאחר מכן כל צאצא מוקצה למרחב התא היחיד עם הכינוי הזה:

.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.story {
  grid-area: story;
  background-size: cover;
  
}

כך ה-HTML שלנו שולט בסדר העריכה, וגם שומר על כל הרכיבים בתנועה. שימו לב שלא נדרשנו לבצע שום פעולה לגבי מיקום absolute או z-index, ולא נדרשנו לסמן את התשובה הנכונה בקופסה באמצעות height: 100% או width: 100%. רשת האב כבר הגדרה את גודל אזור התצוגה של התמונה בסטורי, כך שלא היה צורך להורות לאף אחד מרכיבי הסטורי למלא אותו.

נקודות הצמדה לגלילה ב-CSS

המפרט של נקודות הצמדה לגלילה ב-CSS מאפשר לנעול רכיבים באזור התצוגה בזמן גלילה. לפני שהמאפיינים האלה של CSS היו קיימים, היה צריך להשתמש ב-JavaScript, וזה היה… מסובך, בלשון המעטה. במאמר Introducing CSS Scroll Snap Points של Sarah Drasner מוסבר בפירוט איך משתמשים בהם.

גלילה אופקית ללא סגנונות scroll-snap-points וללא סגנונות scroll-snap-points. בלי ההגדרה הזו, המשתמשים יכולים לגלול באופן חופשי כרגיל. בעזרתו, הדפדפן נשען בעדינות על כל פריט.
הורה
.stories {
  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}
הורה עם גלילה מעבר לקצה מגדיר את התנהגות הצמדת המסך.
צאצא
.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
ילדים יכולים להביע הסכמה להפוך ליעד של Snap.

בחרתי ב'נקודות הצמדה לגלילה' מכמה סיבות:

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

תאימות לדפדפנים שונים

בדקנו את התכונה ב-Opera,‏ Firefox,‏ Safari ו-Chrome, וגם ב-Android וב-iOS. בהמשך מופיעה סקירה קצרה של תכונות האינטרנט שבהן מצאנו הבדלים ביכולות ובתמיכה.

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

scroll-snap-stop

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

.user {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

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

מידע נוסף זמין במפרט.

overscroll-behavior

יצא לכם פעם לגלול בחלון קופץ, ופתאום התחלת לגלול בתוכן שמאחורי החלון הקופץ? overscroll-behavior מאפשר למפתח לפתות את הגלילה ולא לאפשר לה לעזוב. הוא מתאים לכל מיני אירועים. הרכיב 'הסטוריז שלי' משתמש בו כדי למנוע מתנועות החלקה וגלילה נוספות לצאת מהרכיב.

.stories {
  overflow-x: auto;
  overscroll-behavior: contain;
}

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

scrollIntoView({behavior: 'smooth'})

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

element.scrollIntoView({
  behavior: 'smooth'
})

Safari היה הדפדפן היחיד שלא תמך ב-behavior: 'smooth' כאן. כדאי לעיין במאמר תאימות דפדפנים כדי לבדוק אם יש עדכונים.

מעשי

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

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