גלילה מבוקרת באמצעות גלילה ב-CSS

כדי ליצור חוויות גלילה מבוקרות, אפשר להצהיר על מיקומי הצמדה בגלילה.

Robert Flack
Robert Flack
Majid Valipour
Majid Valipour

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

כיסוי להצמדה של גלילה

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

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

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

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

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

צילום מסך של גלילה ב-CSS

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

יכול להיות שמאגר גלילה יתמוך בהצמדה של גלילה באמצעות המאפיין scroll-snap-type. הפעולה הזו מנחה את הדפדפן לחבר את מאגר הגלילה הזה אל מיקומי הצמדה שנוצרים על ידי הצאצאים שלו. scroll-snap-type קובע את הציר שבו מתבצעת הגלילה: x, y או both, ואת הקפדה על הדילוגים: mandatory, proximity. נרחיב בנושא מאוחר יותר.

כדי ליצור מיקום הצמדה, מגדירים את היישור הרצוי לאלמנט. המיקום הזה הוא ההיסט בגלילה שבו מאגר הגלילה של האב הקרוב ביותר והרכיב מיושרים כפי שצוין לציר הנתון. אפשר לבצע את ההתאמות הבאות בכל ציר: start,‏ end,‏ center.

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

דוגמה ליישורים שונים בציר גלילה אופקית.

בדוגמאות הבאות מוסבר איך משתמשים במושגים האלה.

תרחיש לדוגמה נפוץ להצמדה של גלילה היא קרוסלת תמונות. לדוגמה, כדי ליצור קרוסלה של תמונות אופקית שמתמקדת בכל תמונה בזמן הגלילה, אפשר לציין בקונטיינר הגלילה את הערך scroll-snap-type חובה בציר האופק. כדי לוודא שהתמונה תתמקם במרכז הקרוסלה בזמן הגלילה, צריך להגדיר לכל תמונה את הערך scroll-snap-align: center.

#gallery {
  scroll-snap-type: x mandatory;
  overflow-x: scroll;
  display: flex;
}

#gallery img {
   scroll-snap-align: center;
}
<div id="gallery">
  <img src="cat.jpg">
  <img src="dog.jpg">
  <img src="another_cute_animal.jpg">
</div>

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

לצפייה בהדגמה | מקור

דוגמה: דף מוצר שעבר תהליך הרצה

מקרה נפוץ נוסף שבו כדאי להשתמש ב-Snap to Scroll הוא דפים עם כמה קטעים לוגיים שאפשר לגלול ביניהם אנכית, למשל דף מוצר רגיל. scroll-snap-type: y proximity; מתאים יותר לתרחישים כאלה. התכונה לא מפריעה כשהמשתמש גולל לאמצע של קטע מסוים, אלא גם מושכת את תשומת הלב של המשתמשים בקטע חדש כשהם גוללים מספיק קרוב.

כך אפשר לעשות זאת:

article {
  scroll-snap-type: y proximity;
  /* Reserve space for header plus some extra space for sneak peeking. */
  scroll-padding-top: 15vh;
  overflow-y: scroll;
}
section {
  /* Snap align start. */
  scroll-snap-align: start;
}
header {
  position: fixed;
  height: 10vh;
}
<article>
  <header> Header </header>
  <section> Section One </section>
  <section> Section Two </section>
  <section> Section Three </section>
</article>

מרווח פנימי ושוליים

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

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

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

יכול להיות ששמתם לב שבשני המאפיינים האלה לא מופיעה המילה snap. הסיבה לכך היא שהן משנות בפועל את התיבה לכל פעולות הגלילה הרלוונטיות, ולא רק ממקמות את הגלילה. לדוגמה, Chrome מביא אותם בחשבון בחישוב גודל הדף לצורך פעולות גלילה כמו PageDown ו-PageUp, וגם לצורך חישוב כמות הגלילה בפעולה Element.scrollIntoView().

לצפייה בהדגמה | מקור

אינטראקציה עם ממשקי API אחרים לגלילה

DOM Scrolling API

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

גלילה חלקה

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

ההתנהגות של גלילת יתר

Overscroll behavior API קובע איך הגלילה מקושרת בין כמה רכיבים, והוא לא מושפע מהצמדת הגלילה.

אזהרות ושיטות מומלצות

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

במקרים רבים אפשר להוסיף את התכונה של דילוג בין גלילה כשיפור, בלי שיהיה צורך לזהות את התכונה. אם יש צורך, משתמשים ב-@supports או ב-CSS.supports כדי לזהות תמיכה ב-CSS Scroll Snap. הימנעו משימוש ב-scroll-snap-type, שמופיע גם במפרט שהוצא משימוש.

זיהוי תכונות ב-CSS

@supports (scroll-snap-align: start) {
  article {
    scroll-snap-type: y proximity;
    scroll-padding-top: 15vh;
    overflow-y: scroll;
  }
}

זיהוי תכונות ב-JavaScript

if (CSS.supports('scroll-snap-align: start')) {
  // use css scroll snap
} else {
  // use fallback
}

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

עבודות עתידיות

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

  1. זמינות ותאימות של ממשקי API בדפדפנים שונים.
  2. לעבוד על ממשקי CSS API חדשים כמו scroll-start.
  3. עבודה על אירועי JS חדשים כמו snapChanged().