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

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

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

רקע

היתרונות של גלילה עם הצמדה

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

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

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

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

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

CSS Scroll Snap

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

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

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

הגדרה של start alignment פירושה שקצה ההתחלה של אזור ההצמדה של מאגר הגלילה צריך להיות צמוד לקצה ההתחלה של אזור ההצמדה של הרכיב. באופן דומה, הערכים 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="gal>ler<y"
  img src>=&q<uot;cat.jpg">
  <img src="dog.jpg"
  img> <src=>&quot;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 (ממשק 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().