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

יצירת חוויות גלילה מבוקרות על ידי הצהרה על מיקומי הצמדה בגלילה.

Robert Flack
Robert Flack
Majid Valipour
Majid Valipour

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

רקע

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

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

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

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

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>

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

הצגת ההדגמה | מקור

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

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

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

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

הצגת ההדגמה | מקור

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

API לגלילה ב-DOM

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

גלילה חלקה

גלילה חלקה שולטת בהתנהגות של פעולת גלילה פרוגרמטית, בזמן ש-sroll 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().