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

אמ;לק

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

רקע

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

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

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

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

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

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

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

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

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