Xây dựng thành phần Stories

Tổng quan cơ bản về cách tạo trải nghiệm tương tự như Instagram Stories trên web.

Trong bài đăng này, tôi muốn chia sẻ suy nghĩ về việc xây dựng một thành phần Stories cho web có khả năng thích ứng, hỗ trợ thao tác điều hướng bằng bàn phím và hoạt động trên nhiều trình duyệt.

Bản minh hoạ

Nếu bạn muốn tự mình xem bản minh hoạ thực tế về cách tạo thành phần Stories này, hãy xem lớp học lập trình về thành phần Stories.

Nếu bạn thích xem video, thì đây là phiên bản video của bài đăng này trên YouTube:

Tổng quan

Hai ví dụ phổ biến về trải nghiệm người dùng Stories là Snapchat Stories và Instagram Stories (chưa kể đến fleets). Theo thuật ngữ chung về trải nghiệm người dùng, Câu chuyện thường là một mẫu chỉ dành cho thiết bị di động, lấy thao tác nhấn làm trọng tâm để điều hướng nhiều gói thuê bao. Ví dụ: trên Instagram, người dùng mở tin của một người bạn và xem các bức ảnh trong đó. Họ thường làm việc này với nhiều bạn bè cùng một lúc. Khi nhấn vào bên phải thiết bị, người dùng sẽ chuyển sang câu chuyện tiếp theo của người bạn đó. Khi vuốt sang phải, người dùng sẽ chuyển sang một người bạn khác. Thành phần Story (Câu chuyện) khá giống với băng chuyền, nhưng cho phép điều hướng một mảng đa chiều thay vì mảng một chiều. Cứ như thể có một băng chuyền bên trong mỗi băng chuyền. 🤯

Trực quan hoá mảng đa chiều bằng thẻ. Từ trái sang phải là một ngăn xếp gồm các thẻ có đường viền màu tím, bên trong mỗi thẻ là 1 đến nhiều thẻ có đường viền màu lục lam. Danh sách trong danh sách.
Băng chuyền bạn bè thứ nhất
Băng chuyền "xếp chồng" thứ hai gồm các tin
👍 Danh sách trong danh sách, còn gọi là: mảng đa chiều

Chọn công cụ phù hợp cho công việc

Nhìn chung, tôi thấy thành phần này khá dễ xây dựng nhờ một số tính năng quan trọng của nền tảng web. Hãy cùng tìm hiểu về những điểm này!

Lưới CSS

Bố cục của chúng tôi không phải là một yêu cầu quá khó đối với CSS Grid vì nó được trang bị một số cách mạnh mẽ để sắp xếp nội dung.

Bố cục bạn bè

Trình bao bọc thành phần .stories chính của chúng tôi là một scrollview ngang ưu tiên thiết bị di động:

.stories {
  inline-size: 100vw;
  block-size: 100vh;

  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;

  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}

/* desktop constraint */
@media (hover: hover) and (min-width: 480px) {
  max-inline-size: 480px;
  max-block-size: 848px;
}
Sử dụng Chế độ thiết bị của Công cụ dành cho nhà phát triển của Chrome để làm nổi bật các cột do Lưới tạo

Hãy phân tích bố cục grid đó:

  • Chúng tôi điền rõ ràng vào khung nhìn trên thiết bị di động bằng 100vh100vw, đồng thời hạn chế kích thước trên máy tính
  • / phân tách các mẫu hàng và cột của chúng ta
  • auto-flow dịch thành grid-auto-flow: column
  • Mẫu autoflow là 100%, trong trường hợp này là bất kỳ chiều rộng nào của cửa sổ cuộn

Trên điện thoại di động, hãy coi kích thước hàng là chiều cao khung nhìn và mỗi cột là chiều rộng khung nhìn. Tiếp tục với ví dụ về Snapchat Stories và Instagram Stories, mỗi cột sẽ là một tin của bạn bè. Chúng tôi muốn câu chuyện của bạn bè tiếp tục xuất hiện bên ngoài khung hiển thị để người dùng có thể cuộn xuống. Lưới sẽ tạo số lượng cột cần thiết để bố trí HTML cho mỗi câu chuyện của bạn bè, tạo một vùng chứa cuộn linh hoạt và thích ứng cho chúng ta. Lưới giúp chúng tôi tập trung toàn bộ hiệu ứng.

Xếp chồng

Đối với mỗi người bạn, chúng ta cần câu chuyện của họ ở trạng thái sẵn sàng phân trang. Để chuẩn bị cho ảnh động và các mẫu thú vị khác, tôi đã chọn một ngăn xếp. Khi nói xếp chồng, tôi muốn nói đến việc bạn nhìn xuống một chiếc bánh mì kẹp, chứ không phải nhìn từ bên cạnh.

Với lưới CSS, chúng ta có thể xác định một lưới ô đơn (tức là một hình vuông), trong đó các hàng và cột dùng chung một bí danh ([story]), sau đó mỗi phần tử con được chỉ định cho không gian ô đơn có bí danh đó:

.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.story {
  grid-area: story;
  background-size: cover;
  
}

Điều này giúp HTML kiểm soát thứ tự xếp chồng và cũng giữ cho tất cả các phần tử nằm trong luồng. Lưu ý rằng chúng ta không cần làm gì với việc định vị absolute hoặc z-index và chúng ta không cần đóng khung chính xác bằng height: 100% hoặc width: 100%. Lưới mẹ đã xác định kích thước của khung hiển thị ảnh trong tin, vì vậy không cần phải yêu cầu bất kỳ thành phần nào trong số này lấp đầy khung hiển thị đó!

Điểm chụp cuộn CSS

Quy cách CSS Scroll Snap Points giúp bạn dễ dàng khoá các phần tử vào khung nhìn khi cuộn. Trước khi các thuộc tính CSS này xuất hiện, bạn phải sử dụng JavaScript và điều này ít nhất cũng là một việc khó khăn. Hãy xem bài viết Giới thiệu về điểm chụp cuộn CSS của Sarah Drasner để biết thông tin chi tiết về cách sử dụng các điểm này.

Cuộn ngang không có và có kiểu scroll-snap-points. Nếu không có tham số này, người dùng có thể cuộn tự do như bình thường. Nhờ đó, trình duyệt sẽ dừng lại ở từng mục.
mẹ
.stories {
  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}
Phần tử mẹ có tính năng cuộn quá mức xác định hành vi chụp nhanh.
đứa trẻ
.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
Các thành phần con chọn trở thành mục tiêu chụp nhanh.

Tôi chọn Scroll Snap Points vì một số lý do sau:

  • Hỗ trợ tiếp cận miễn phí. Quy cách Điểm cuộn nhanh nêu rõ rằng theo mặc định, khi nhấn các phím Mũi tên tráiMũi tên phải, người dùng sẽ di chuyển qua các điểm cuộn nhanh.
  • Một quy cách ngày càng phát triển. Quy cách Scroll Snap Points (Điểm cuộn nhanh) luôn có các tính năng và điểm cải tiến mới. Điều này có nghĩa là thành phần Stories (Tin) của tôi có thể sẽ chỉ cải thiện hơn nữa từ đây trở đi.
  • Dễ dàng triển khai. Scroll Snap Points (Điểm cuộn nhanh) được thiết kế cho trường hợp sử dụng phân trang ngang tập trung vào thao tác chạm.
  • Quán tính kiểu nền tảng tự do. Mỗi nền tảng sẽ cuộn và dừng theo kiểu riêng, thay vì quán tính được chuẩn hoá có thể có kiểu cuộn và dừng kỳ lạ.

Khả năng tương thích trên nhiều trình duyệt

Chúng tôi đã thử nghiệm trên Opera, Firefox, Safari và Chrome, cũng như Android và iOS. Sau đây là thông tin tóm tắt về các tính năng trên web mà chúng tôi nhận thấy có sự khác biệt về chức năng và khả năng hỗ trợ.

Tuy nhiên, chúng tôi đã không áp dụng một số CSS, vì vậy, một số nền tảng hiện đang bỏ lỡ các hoạt động tối ưu hoá trải nghiệm người dùng. Tôi rất hài lòng khi không cần quản lý các tính năng này và tin rằng chúng sẽ có mặt trên các trình duyệt và nền tảng khác trong tương lai.

scroll-snap-stop

Băng chuyền là một trong những trường hợp sử dụng chính về trải nghiệm người dùng, thúc đẩy việc tạo ra quy cách Điểm chụp nhanh khi cuộn CSS. Không giống như Stories, băng chuyền không phải lúc nào cũng cần dừng ở mỗi hình ảnh sau khi người dùng tương tác với băng chuyền. Bạn có thể vuốt nhanh qua băng chuyền hoặc nên làm như vậy. Mặt khác, bạn nên xem từng tin riêng lẻ và đó chính xác là những gì scroll-snap-stop cung cấp.

.user {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

Tại thời điểm viết bài đăng này, scroll-snap-stop chỉ được hỗ trợ trên các trình duyệt dựa trên Chromium. Hãy xem phần Khả năng tương thích với trình duyệt để biết thông tin mới nhất. Tuy nhiên, đây không phải là vấn đề chặn. Điều này chỉ có nghĩa là trên các trình duyệt không được hỗ trợ, người dùng có thể vô tình bỏ qua một người bạn. Vì vậy, người dùng chỉ cần cẩn thận hơn hoặc chúng ta cần viết JavaScript để đảm bảo rằng một người bạn bị bỏ qua không được đánh dấu là đã xem.

Hãy đọc thêm trong bản đặc tả nếu bạn quan tâm.

overscroll-behavior

Bạn đã bao giờ cuộn qua một phương thức mà đột nhiên bạn bắt đầu cuộn nội dung phía sau phương thức đó chưa? overscroll-behaviorcho phép nhà phát triển chặn thao tác cuộn đó và không bao giờ để thao tác đó rời đi. Đây là một lựa chọn phù hợp cho mọi dịp. Thành phần Câu chuyện của tôi sử dụng nó để ngăn các cử chỉ vuốt và cuộn bổ sung rời khỏi thành phần.

.stories {
  overflow-x: auto;
  overscroll-behavior: contain;
}

Safari và Opera là 2 trình duyệt không hỗ trợ tính năng này và điều đó hoàn toàn bình thường. Những người dùng đó sẽ có trải nghiệm cuộn quá mức như họ vẫn thường dùng và có thể không bao giờ nhận thấy điểm cải tiến này. Cá nhân tôi là một người hâm mộ lớn và thích đưa tính năng này vào gần như mọi tính năng cuộn quá mức mà tôi triển khai. Đây là một điểm bổ sung vô hại và chỉ có thể giúp cải thiện trải nghiệm người dùng.

scrollIntoView({behavior: 'smooth'})

Khi người dùng nhấn hoặc nhấp và đã xem hết một nhóm tin của bạn bè, thì đã đến lúc chuyển sang người bạn tiếp theo trong nhóm điểm dừng cuộn. Với JavaScript, chúng tôi có thể tham chiếu đến người bạn tiếp theo và yêu cầu người bạn đó được cuộn vào chế độ xem. Khả năng hỗ trợ cho những điều cơ bản của tính năng này rất tốt; mọi trình duyệt đều cuộn tính năng này vào chế độ xem. Nhưng không phải trình duyệt nào cũng làm được điều này 'smooth'. Điều này chỉ có nghĩa là thành phần đó được cuộn vào chế độ xem thay vì được điều chỉnh.

element.scrollIntoView({
  behavior: 'smooth'
})

Safari là trình duyệt duy nhất không hỗ trợ behavior: 'smooth' tại đây. Hãy xem phần Khả năng tương thích với trình duyệt để biết thông tin mới nhất.

Thực hành

Giờ bạn đã biết cách tôi làm, vậy bạn sẽ làm như thế nào?! Hãy đa dạng hoá các phương pháp và tìm hiểu tất cả các cách để xây dựng trên web. Tạo một Glitch, tweet cho tôi phiên bản của bạn và tôi sẽ thêm phiên bản đó vào phần Bản phối lại của cộng đồng bên dưới.

Bản phối lại của cộng đồng