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

אריק בידלמן
מג'יד ואליפור

אמ;לק

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

רקע

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

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

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

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

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

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

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

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

יש לנו אפשרות להשתפר!

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

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