Kiểm soát thao tác cuộn – tuỳ chỉnh các hiệu ứng kéo để làm mới và mục bổ sung

TL;DR

Thuộc tính CSS overscroll-behavior cho phép nhà phát triển ghi đè hành vi cuộn mục bổ sung mặc định của trình duyệt khi đến đầu/cuối nội dung. Các trường hợp sử dụng bao gồm tắt tính năng kéo để làm mới trên thiết bị di động, xoá hiệu ứng phát sáng cuộn quá mức và hiệu ứng dải cao su, đồng thời ngăn nội dung trang cuộn khi ở dưới một phương thức/lớp phủ.

Thông tin khái quát

Cuộn ranh giới và tạo chuỗi cuộn

Tạo chuỗi trên Chrome Android.

Cuộn là một trong những cách cơ bản nhất để tương tác với trang, nhưng một số mẫu trải nghiệm người dùng nhất định có thể khó xử lý do các hành vi mặc định độc đáo của trình duyệt. Ví dụ: hãy lấy một ngăn ứng dụng có nhiều mục mà người dùng có thể phải cuộn qua. Khi chúng cuộn xuống dưới cùng, vùng chứa bổ sung sẽ ngừng cuộn vì không còn nội dung nào để sử dụng. Nói cách khác, người dùng đạt đến "ranh giới cuộn". Nhưng hãy chú ý điều gì sẽ xảy ra nếu người dùng tiếp tục cuộn. Nội dung phía sau ngăn bắt đầu cuộn! Vùng chứa mẹ sẽ kiểm soát thao tác cuộn; ví dụ là chính trang chính.

Hoá ra hành vi này được gọi là chuỗi cuộn; hành vi mặc định của trình duyệt khi cuộn nội dung. Thông thường, chế độ mặc định khá tốt, nhưng đôi khi nó không như mong đợi hoặc thậm chí là không như mong đợi. Một số ứng dụng có thể muốn cung cấp trải nghiệm người dùng khác khi người dùng đạt đến ranh giới cuộn.

Hiệu ứng kéo để làm mới

Kéo để làm mới là một cử chỉ trực quan được các ứng dụng di động như Facebook và Twitter phổ biến. Việc kéo xuống nguồn cấp dữ liệu mạng xã hội và phát hành sẽ tạo không gian mới để tải các bài đăng gần đây hơn. Trên thực tế, trải nghiệm người dùng cụ thể này đã phổ biến đến mức các trình duyệt dành cho thiết bị di động như Chrome trên Android cũng áp dụng hiệu quả tương tự. Việc vuốt xuống đầu trang sẽ làm mới toàn bộ trang:

Tính năng kéo để làm mới tuỳ chỉnh của Twitter
khi làm mới nguồn cấp dữ liệu trong PWA của họ.
Thao tác kéo để làm mới gốc của Chrome Android
sẽ làm mới toàn bộ trang.

Đối với các trường hợp như PWA trên Twitter, bạn có thể tắt thao tác kéo để làm mới gốc. Vì sao lại như vậy? Trong ứng dụng này, có thể bạn không muốn người dùng vô tình làm mới trang. Bạn cũng có thể thấy ảnh động làm mới hai lần! Ngoài ra, bạn nên tuỳ chỉnh hành động của trình duyệt để phù hợp hơn với thương hiệu của trang web. Đáng tiếc là loại tuỳ chỉnh này khó thực hiện. Các nhà phát triển sẽ viết JavaScript không cần thiết, thêm trình nghe cảm ứng không thụ động (chặn cuộn) hoặc gắn toàn bộ trang trong một <div> 100vw/vh (để ngăn trang bị tràn). Các giải pháp này có tác động tiêu cực đến hiệu suất cuộn được ghi nhận rõ ràng.

Chúng tôi có thể làm tốt hơn!

Xin giới thiệu overscroll-behavior

Thuộc tính overscroll-behavior là một tính năng CSS mới kiểm soát hành vi của những gì xảy ra khi bạn cuộn quá mức một vùng chứa (bao gồm cả chính trang đó). Bạn có thể sử dụng công cụ này để huỷ chuỗi cuộn, tắt/tuỳ chỉnh thao tác kéo để làm mới, tắt hiệu ứng dải cao su trên iOS (khi Safari triển khai overscroll-behavior) và làm nhiều việc khác. Điều đáng chú ý nhất là việc sử dụng overscroll-behavior không ảnh hưởng xấu đến hiệu suất trang như các thủ thuật được đề cập trong phần giới thiệu!

Thuộc tính này có thể nhận 3 giá trị:

  1. auto – Mặc định. Các lượt cuộn bắt nguồn từ phần tử này có thể truyền đến các phần tử đối tượng cấp trên.
  2. contain (chứa) – ngăn chặn việc tạo chuỗi cuộn. Các lượt cuộn không truyền đến đối tượng cấp trên nhưng các hiệu ứng cục bộ trong nút sẽ hiển thị. Ví dụ: hiệu ứng phát sáng cuộn quá mức trên Android hoặc hiệu ứng dải cao su trên iOS thông báo cho người dùng khi họ đạt đến ranh giới cuộn. Lưu ý: việc sử dụng overscroll-behavior: contain trên phần tử html sẽ ngăn các thao tác điều hướng cuộn quá mức.
  3. none – giống như contain nhưng cũng ngăn các hiệu ứng cuộn quá mức trong chính nút (ví dụ: ánh sáng cuộn quá mức trên Android hoặc dải cao su của iOS).

Hãy cùng tìm hiểu một số ví dụ để biết cách sử dụng overscroll-behavior.

Ngăn thao tác cuộn thoát khỏi một phần tử vị trí cố định

Tình huống hộp trò chuyện

Nội dung bên dưới cửa sổ trò chuyện cũng sẽ cuộn theo :(

Hãy cân nhắc đặt hộp trò chuyện cố định ở cuối trang. Mục đích của hộp trò chuyện là một thành phần độc lập và cuộn riêng biệt với nội dung phía sau. Tuy nhiên, do chuỗi cuộn, tài liệu bắt đầu cuộn ngay khi người dùng nhấn vào tin nhắn cuối cùng trong nhật ký trò chuyện.

Đối với ứng dụng này, việc đặt các thao tác cuộn trong hộp trò chuyện ở trong cuộc trò chuyện sẽ phù hợp hơn. Chúng ta có thể làm việc đó bằng cách thêm overscroll-behavior: contain vào phần tử lưu giữ tin nhắn trò chuyện:

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

Về cơ bản, chúng tôi đang tạo ra sự phân tách hợp lý giữa ngữ cảnh cuộn của hộp trò chuyện và trang chính. Kết quả cuối cùng là trang chính vẫn ở lại khi người dùng chuyển đến đầu/cuối nhật ký trò chuyện. Các nội dung cuộn bắt đầu trong hộp trò chuyện sẽ không lan truyền.

Trường hợp lớp phủ trang

Một biến thể khác của trường hợp "cuộn dưới" là khi bạn thấy nội dung cuộn sau lớp phủ vị trí cố định. Sắp có một chương trình tặng quà không thể bỏ qua overscroll-behavior! Trình duyệt đang cố gắng trở nên hữu ích nhưng rốt cuộc nó lại khiến trang web trông có lỗi.

Ví dụ – cửa sổ phụ có và không có overscroll-behavior: contain:

Trước: nội dung trang cuộn bên dưới lớp phủ.
Sau: nội dung trang không cuộn dưới lớp phủ.

Tắt tính năng kéo để làm mới

Tắt thao tác kéo để làm mới là một dòng CSS duy nhất. Chỉ cần ngăn việc tạo chuỗi trên toàn bộ phần tử xác định khung nhìn. Trong hầu hết các trường hợp, đó là <html> hoặc <body>:

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

Với thao tác bổ sung đơn giản này, chúng tôi sẽ khắc phục hai ảnh động kéo để làm mới trong bản minh hoạ hộp trò chuyện và thay vào đó, có thể triển khai hiệu ứng tuỳ chỉnh sử dụng ảnh động tải gọn gàng hơn. Toàn bộ hộp thư đến cũng bị làm mờ khi hộp thư đến làm mới:

Trước
Sau

Dưới đây là đoạn mã của mã đầy đủ:

<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>

Tắt hiệu ứng ánh sáng cuộn quá mức và dải cao su

Để tắt hiệu ứng nảy khi đạt đến ranh giới cuộn, hãy sử dụng overscroll-behavior-y: none:

body {
  /* Disables pull-to-refresh and overscroll glow effect.
     Still keeps swipe navigations. */
  overscroll-behavior-y: none;
}
Trước: khi nhấn vào ranh giới cuộn, bạn sẽ thấy một tia sáng.
Sau: tính năng phát sáng bị tắt.

Bản minh hoạ đầy đủ

Kết hợp tất cả lại với nhau, bản minh hoạ hộp trò chuyện đầy đủ sử dụng overscroll-behavior để tạo một ảnh động tuỳ chỉnh kéo để làm mới và vô hiệu hoá thao tác cuộn để thoát khỏi tiện ích hộp trò chuyện. Điều này mang lại trải nghiệm người dùng tối ưu mà khó có thể đạt được nếu không có CSS overscroll-behavior.

Xem bản minh hoạ | Nguồn