שליטה בגלילה – התאמה אישית של אפקטים של 'משיכה לרענון' ו'אפשרויות נוספות'

אמ;לק

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

רקע

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

שרשור גלילה ב-Chrome ל-Android.

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

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

האפקט של 'משיכה לרענון'

'משיכה לרענון' היא מחווה אינטואיטיבית שצוברת פופולריות באפליקציות לנייד כמו Facebook ו-Twitter. כשמושכים למטה את הפיד של הרשת החברתית ומשחררים, נוצר מקום חדש שבו נטענים פוסטים עדכניים יותר. למעשה, חוויית המשתמש הזו הפכה לפופולרית כל כך, שדפדפנים לנייד כמו Chrome ל-Android אימצו את אותו אפקט. החלקה למטה בחלק העליון של הדף מרעננת את הדף כולו:

משיכה לרענון בהתאמה אישית של Twitter
כשמרעננים פיד ב-PWA.
פעולת 'משיכה לרענון' המובנית של Chrome ל-Android
מרעננת את הדף כולו.

במצבים כמו PWA, מומלץ להשבית את הפעולה המקורית של משיכה לרענון. למה? באפליקציה הזו, סביר להניח שלא תרצו שהמשתמש ירענן את הדף בטעות. יכול להיות שתראו גם אנימציה כפולה של רענון. לחלופין, יכול להיות שיהיה נחמד יותר להתאים אישית את הפעולה של הדפדפן, כך שתתאים יותר למיתוג של האתר. לצערנו, ההתאמה האישית הזו הייתה מורכבת מאוד. בסופו של דבר, המפתחים כותבים JavaScript מיותר, מוסיפים פונקציות מקישים לא פסיביות (שחוסמות גלילה) או מדביקים את כל הדף ב-<div> 100v/vh (כדי למנוע גלישת דף). יש להן השפעות שליליות מוכרות על הביצועים של גלילה.

אנחנו יכולים לעשות טוב יותר!

חדש: overscroll-behavior

המאפיין overscroll-behavior הוא תכונה חדשה ב-CSS ששולטת בהתנהגות שמתרחשת כשגוללים מעבר לקו העליון של מאגר (כולל הדף עצמו). אפשר להשתמש בו כדי לבטל שרשור גלילה, להשבית או להתאים אישית את הפעולה של משיכה לרענון, להשבית את האפקטים של 'גמישות' ב-iOS (כש-Safari מטמיע את overscroll-behavior) ועוד. החלק הכי טוב הוא שהשימוש ב-overscroll-behavior לא משפיע לרעה על ביצועי הדף, בניגוד לפריצות שצוינו בפתיח.

המאפיין מקבל שלושה ערכים אפשריים:

  1. auto – ברירת מחדל. גלילות שמקורן ברכיב עשויות להופיע ברכיבי האב.
  2. contain - מניעת שרשרת גלילה. גלילות לא מועברות לצאצאים, אבל השפעות מקומיות בתוך הצומת מוצגות. לדוגמה, אפקט ההילה של גלילה מעבר לקצה המסך ב-Android או אפקט הגומי ב-iOS, שמציג הודעה למשתמש כשהוא מגיע לקצה המסך. הערה: שימוש ב-overscroll-behavior: contain ברכיב html מונע פעולות ניווט של גלילה מעבר לקצה המסך.
  3. none – זהה ל-contain אבל הוא גם מונע אפקטים של גלילת יתר בתוך הצומת עצמו (למשל, זוהר בגלילת יתר ב-Android או גומי ב-iOS).

נבחן כמה דוגמאות כדי להבין איך משתמשים ב-overscroll-behavior.

מניעת האפשרות של גלילות לבלוט לרכיב מיקום קבוע

התרחיש של תיבת הצ'אט

התוכן שמתחת לחלון הצ'אט גולל גם כן :(

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

באפליקציה הזו, עדיף שהגלילה תתבצע בתוך תיבת הצ'אט. כדי לעשות זאת, מוסיפים את הערך overscroll-behavior: contain לרכיב שמכיל את הודעות הצ'אט:

#chat .msgs {
  overflow: auto;
  overscroll-behavior: contain;
  height: 300px;
}

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

התרחיש של שכבת-העל בדף

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

דוגמה – חלון דו-שיח עם overscroll-behavior: contain וללא overscroll-behavior: contain:

לפני: תוכן הדף גולל מתחת לשכבת-העל.
אחרי: תוכן הדף לא נגלל מתחת לשכבת-על.

השבתת 'משיכה לרענון'

השבתה של הפעולה 'משיכה לרענון' היא שורה אחת של CSS. פשוט מנעו גלילה לשרשראות של כל הרכיב שמגדיר אזור תצוגה. ברוב המקרים, זהו הערך <html> או <body>:

body {
  /* Disables pull-to-refresh but allows overscroll glow effects. */
  overscroll-behavior-y: contain;
}

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

לפני
אחרי

לפניכם קטע מתוך הקוד המלא:

<style>
  body.refreshing #inbox {
    filter: blur(1px);
    touch-action: none; /* prevent scrolling */
  }
  body.refreshing .refresher {
    transform: translate3d(0,150%,0) scale(1);
    z-index: 1;
  }
  .refresher {
    --refresh-width: 55px;
    pointer-events: none;
    width: var(--refresh-width);
    height: var(--refresh-width);
    border-radius: 50%;
    position: absolute;
    transition: all 300ms cubic-bezier(0,0,0.2,1);
    will-change: transform, opacity;
    ...
  }
</style>

<div class="refresher">
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
</div>

<section id="inbox"><!-- msgs --></section>

<script>
  let _startY;
  const inbox = document.querySelector('#inbox');

  inbox.addEventListener('touchstart', e => {
    _startY = e.touches[0].pageY;
  }, {passive: true});

  inbox.addEventListener('touchmove', e => {
    const y = e.touches[0].pageY;
    // Activate custom pull-to-refresh effects when at the top of the container
    // and user is scrolling up.
    if (document.scrollingElement.scrollTop === 0 && y > _startY &&
        !document.body.classList.contains('refreshing')) {
      // refresh inbox.
    }
  }, {passive: true});
</script>

השבתת האפקטים של זוהר בגלילה מעבר לקצה המסך ואפקט הגומי

כדי להשבית את אפקט ההחזרה אחרי שמגיעים לגבול גלילה, משתמשים ב-overscroll-behavior-y: none:

body {
  /* Disables pull-to-refresh and overscroll glow effect.
     Still keeps swipe navigations. */
  overscroll-behavior-y: none;
}
לפני: כשמגיעים לקצה הגלילה מופיע זוהר.
אחרי: הארה מושבתת.

הדגמה מלאה

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

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