ควบคุมการเลื่อนของคุณ - ปรับแต่งเอฟเฟกต์การดึงเพื่อรีเฟรชและเอฟเฟกต์เพิ่มเติม

สรุปคร่าวๆ

พร็อพเพอร์ตี้ CSS overscroll-behavior ช่วยให้นักพัฒนาซอฟต์แวร์ลบล้างลักษณะการทำงานของการเลื่อนรายการเพิ่มเติมเริ่มต้นของเบราว์เซอร์เมื่อไปถึงด้านบน/ด้านล่างของเนื้อหาได้ กรณีการใช้งานได้แก่ การปิดใช้ฟีเจอร์ดึงเพื่อรีเฟรชในอุปกรณ์เคลื่อนที่ การนำเอฟเฟกต์การเรืองแสงและแถบยางสำหรับการเลื่อนมากเกินไปออก และการป้องกันไม่ให้เนื้อหาเลื่อนหน้าเว็บเมื่อเนื้อหาอยู่ภายใต้โมดัล/การวางซ้อน

ที่มา

ขอบเขตการเลื่อนและเชนการเลื่อน

เชนการเลื่อนใน Chrome Android

การเลื่อนเป็นหนึ่งในวิธีพื้นฐานที่สุดในการโต้ตอบกับหน้าเว็บ แต่รูปแบบ UX บางรูปแบบอาจจัดการได้ยากเนื่องจากพฤติกรรมเริ่มต้นสุดแปลกของเบราว์เซอร์ ตัวอย่างเช่น ดูลิ้นชักแอปซึ่งมีรายการ จำนวนมากที่ผู้ใช้อาจต้องเลื่อนดู เมื่อเลื่อนลงไปถึงด้านล่าง คอนเทนเนอร์รายการเพิ่มเติมจะหยุดเลื่อนเพราะไม่มีเนื้อหาที่จะอ่านแล้ว กล่าวคือ ผู้ใช้ไปถึง "ขอบเขตการเลื่อน" แล้ว แต่ให้สังเกตว่าจะเกิดอะไรขึ้นหากผู้ใช้ยังคงเลื่อนต่อไป เนื้อหาด้านหลังลิ้นชักเริ่มเลื่อนลง! การเลื่อนจะเข้ามาแทนที่คอนเทนเนอร์ระดับบนสุด ซึ่งก็คือหน้าหลักเองในตัวอย่าง

ซึ่งพฤติกรรมนี้เรียกว่าห่วงโซ่การเลื่อน ซึ่งเป็นลักษณะการทำงานเริ่มต้นของเบราว์เซอร์เมื่อเลื่อนเนื้อหา บ่อยครั้งที่ค่าเริ่มต้นค่อนข้างดี แต่บางครั้งก็อาจไม่เป็นที่ต้องการหรือแม้แต่ไม่คาดคิด แอปบางแอปอาจต้องการมอบประสบการณ์ของผู้ใช้ที่แตกต่างออกไปเมื่อผู้ใช้มาถึงขอบเขตการเลื่อน

เอฟเฟ็กต์การดึงเพื่อรีเฟรช

การดึงเพื่อรีเฟรชเป็นท่าทางสัมผัสที่ใช้งานง่ายซึ่งเป็นที่นิยมในแอปบนอุปกรณ์เคลื่อนที่ เช่น Facebook และ Twitter การดึงฟีดโซเชียลแล้วเผยแพร่จะสร้างพื้นที่ใหม่เพื่อให้โหลดโพสต์ใหม่ๆ ได้ อันที่จริงแล้ว UX ที่เจาะจงนี้เริ่มได้รับความนิยมมากจนเบราว์เซอร์ในอุปกรณ์เคลื่อนที่อย่าง Chrome ใน Android ได้รับผลแบบเดียวกัน การเลื่อนลงที่ด้านบนของหน้าจะรีเฟรชทั้งหน้า ดังนี้

การดึงเพื่อรีเฟรชที่กำหนดเองของ Twitter
เมื่อรีเฟรชฟีดใน PWA
การดึงเพื่อรีเฟรชในเครื่องของ Chrome Android
จะรีเฟรชทั้งหน้าเว็บ

สำหรับสถานการณ์ต่างๆ เช่น PWA ของ Twitter การปิดใช้การทำงานแบบดึงเพื่อรีเฟรชในเครื่องอาจเป็นเรื่องที่เหมาะสม เหตุผล ในแอปนี้ คุณคงไม่ต้องการให้ผู้ใช้รีเฟรชหน้าเว็บโดยไม่ตั้งใจ คุณอาจจะเห็นภาพเคลื่อนไหว ที่รีเฟรช 2 ครั้งด้วย หรือปรับการทำงานของเบราว์เซอร์ให้ใกล้เคียงกับการสร้างแบรนด์ของไซต์มากกว่า อาจจะดีกว่า เรื่องน่าเสียดายคือ การปรับแต่งประเภทนี้เป็นอะไรที่ซับซ้อนมากๆ นักพัฒนาซอฟต์แวร์จบลงด้วยการเขียน JavaScript ที่ไม่จำเป็น เพิ่ม Listener แบบสัมผัสแบบไม่ใช่แพสซีฟ (ซึ่งบล็อกการเลื่อน) หรือติด 100vw/vh <div> ทั้งหน้า (เพื่อป้องกันไม่ให้หน้าล้น) การแก้ปัญหาชั่วคราวเหล่านี้ส่งผลกระทบเชิงลบต่อประสิทธิภาพการเลื่อนที่มีการบันทึกไว้เป็นอย่างดี

เราทำได้ดีกว่านี้

ขอแนะนำ overscroll-behavior

พร็อพเพอร์ตี้ overscroll-behavior เป็นฟีเจอร์ CSS ใหม่ที่ควบคุมลักษณะการทำงานของสิ่งที่เกิดขึ้นเมื่อคุณเลื่อนคอนเทนเนอร์ (รวมถึงตัวหน้าเว็บเอง) มากเกินไป คุณสามารถใช้เพื่อยกเลิกห่วงโซ่การเลื่อน ปิดใช้/ปรับแต่งการทำงานแบบดึงเพื่อรีเฟรช ปิดใช้เอฟเฟกต์ยางใน iOS (เมื่อ Safari ใช้ overscroll-behavior) และอื่นๆ ส่วนที่ดีที่สุดคือการใช้ overscroll-behavior ไม่ส่งผลเสียต่อประสิทธิภาพของหน้าเว็บเหมือนเคล็ดลับที่บอกไว้ในช่วงอินโทร

พร็อพเพอร์ตี้ใช้ค่าที่เป็นไปได้ 3 ค่า ดังนี้

  1. auto - ค่าเริ่มต้น การเลื่อนที่เริ่มจากองค์ประกอบอาจเผยแพร่ไปยังองค์ประกอบระดับบน
  2. contain - ป้องกันห่วงโซ่การเลื่อน การเลื่อนจะไม่ถ่ายทอดไปยังระดับบน แต่จะแสดงเอฟเฟกต์ในเครื่องภายในโหนด ตัวอย่างเช่น เอฟเฟกต์การเรืองแสงเหนือระดับใน Android หรือเอฟเฟกต์ยางบน iOS ซึ่งจะแจ้งเตือนเมื่อผู้ใช้ไปถึงขอบเขตการเลื่อน หมายเหตุ: การใช้ overscroll-behavior: contain ในองค์ประกอบ html จะป้องกันไม่ให้มีการไปยังส่วนต่างๆ มากเกินไป
  3. ไม่มี - เหมือนกับ 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;
}

ด้วยการเพิ่มเอฟเฟกต์ง่ายๆ นี้ เราจะแก้ไขภาพเคลื่อนไหวแบบดึงเพื่อรีเฟรช 2 ครั้งในการสาธิตช่องแชทและใช้เอฟเฟกต์ที่กำหนดเองซึ่งใช้ภาพเคลื่อนไหวการโหลดแบบเนี้ยบแทนได้ กล่องจดหมายทั้งกล่องยังเบลอขณะที่กล่องจดหมายรีเฟรชอีกด้วย ดังนี้

ก่อน
หลัง

นี่คือข้อมูลโค้ดโค้ดแบบเต็ม

<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

ดูการสาธิต | แหล่งที่มา