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

אמ;לק

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

רקע

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

גלילה בגלילה ב-Chrome Android.

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

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

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

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

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

במצבים כמו PWA של Twitter, כדאי להשבית את פעולת המשיכה לרענון המקורית. למה? באפליקציה הזו, סביר להניח שלא תרצו שהמשתמש ירענן את הדף בטעות. אפשר גם לראות אנימציה של רענון כפול. לחלופין, יכול להיות שעדיף להתאים אישית את פעולת הדפדפן, ולהתאים אותה יותר למיתוג של האתר. לצערנו, ההתאמה האישית הזו הייתה מורכבת מאוד. בסופו של דבר, המפתחים כותבים JavaScript מיותר, מוסיפים פונקציות event listener לא פסיביות (שחוסמות גלילה) או מדביקים את כל הדף ב-<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:

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

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

השבתה של פעולת המשיכה לרענון היא שורה אחת של 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 כדי ליצור אנימציה מותאמת אישית של משיכה לרענון, ולהשבית את האפשרות של גלילות לסמן בתו בריחה (escape) בווידג'ט של תיבת הצ'אט. כך חוויית המשתמש האופטימלית הייתה קשה להשיג בלי CSS. overscroll-behavior.

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