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

CSS Scroll Snap

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

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

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

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

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

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

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

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

דוגמה: דף מוצר שמשתמשים הגיעו אליו אחרי מסלול המרה

תרחיש נפוץ נוסף שבו כדאי להשתמש בהצמדה לגלילה הוא דפים עם כמה חלקים לוגיים שאפשר לגלול ביניהם אנכית, למשל דף מוצר טיפוסי. 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 inset נוסף למעלה, שמורה לדפדפן להתייחס למיקום נמוך יותר, 15vh מתחת לקצה העליון של מאגר הגלילה, כקצה ההתחלה האנכי שלו לקיבוע הגלילה. כשמצמידים, קצה ההתחלה של רכיב היעד להצמדה יהיה צמוד למיקום החדש, ולכן יישאר רווח מעליו.

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

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

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

DOM Scrolling API

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

גלילה חלקה

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

התנהגות גלילה מעבר לקצה

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. עבודה על ממשקי API חדשים של CSS כמו scroll-start.
  3. עובדים על אירועי JS חדשים כמו snapChanged().