Xây dựng thành phần của trình cuộn nội dung nghe nhìn

Thông tin tổng quan cơ bản về cách tạo chế độ xem cuộn ngang thích ứng cho TV, điện thoại, máy tính, v.v.

Trong bài đăng này, tôi muốn chia sẻ suy nghĩ về cách tạo trải nghiệm cuộn ngang cho web tối thiểu, đáp ứng, truy cập được và hoạt động trên các trình duyệt và nền tảng (như TV!). Hãy thử bản minh hoạ.

Bản minh hoạ

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

Tổng quan

Chúng ta sẽ xây dựng một bố cục cuộn theo chiều ngang nhằm lưu trữ hình thu nhỏ của nội dung nghe nhìn hoặc sản phẩm. Thành phần bắt đầu dưới dạng một danh sách <ul> đơn giản nhưng được chuyển đổi với CSS thành trải nghiệm cuộn thoải mái và mượt mà, hiển thị hình ảnh và đưa hình ảnh vào một lưới. JavaScript được thêm vào để hỗ trợ các hoạt động tương tác với chỉ mục di động, giúp người dùng bàn phím bỏ qua việc truyền tải hơn 100 mục. Ngoài ra, truy vấn nội dung nghe nhìn thử nghiệm (prefers-reduced-data) được dùng để biến trình cuộn nội dung nghe nhìn thành một trải nghiệm gọn nhẹ khi cuộn tiêu đề.

Bắt đầu bằng mã đánh dấu có thể truy cập

Công cụ cuộn nội dung đa phương tiện chỉ bao gồm một vài thành phần cốt lõi, đó là một danh sách chứa các mục. Ở dạng đơn giản nhất, danh sách có thể di chuyển khắp nơi trên thế giới và được tất cả mọi người sử dụng rõ ràng. Người dùng đến trang này có thể duyệt xem danh sách và nhấp vào đường liên kết để xem mặt hàng. Đây là phiên bản cơ sở hỗ trợ tiếp cận của chúng tôi.

Cung cấp danh sách có phần tử <ul>:

<ul class="horizontal-media-scroller">
  <li></li>
  <li></li>
  <li></li>
  ...
<ul>

Tạo tính tương tác cho các mục trong danh sách bằng phần tử <a>:

<li>
  <a href="#">
    ...
  </a>
</li>

Sử dụng phần tử <figure> để biểu thị hình ảnh và chú thích về mặt ngữ nghĩa:

<figure>
  <picture>
    <img alt="..." loading="lazy" src="https://picsum.photos/500/500?1">
  </picture>
  <figcaption>Legends</figcaption>
</figure>

Hãy lưu ý thuộc tính altloading trên <img>. Văn bản thay thế cho thanh cuộn nội dung đa phương tiện là cơ hội trải nghiệm người dùng để cung cấp thêm ngữ cảnh cho hình thu nhỏ hoặc dưới dạng văn bản dự phòng nếu hình ảnh không tải, hoặc cung cấp giao diện người dùng dạng nói cho những người dùng sử dụng công nghệ hỗ trợ như trình đọc màn hình. Tìm hiểu thêm qua 5 quy tắc vàng cho văn bản thay thế tuân thủ chính sách.

Thuộc tính loading chấp nhận từ khoá lazy như một cách để báo hiệu rằng nguồn hình ảnh này sẽ chỉ được tìm nạp khi hình ảnh nằm trong khung nhìn. Cách này thực sự hữu ích đối với danh sách lớn, vì người dùng sẽ chỉ tải hình ảnh cho các mục mà họ đã cuộn vào khung hiển thị.

Hỗ trợ lựa chọn ưu tiên của người dùng trong bảng phối màu

Sử dụng color-scheme làm thẻ <meta> để báo cho trình duyệt biết rằng trang của bạn muốn có cả kiểu tác nhân người dùng sáng lẫn tối được cung cấp. Đó là chế độ tối hoặc chế độ sáng miễn phí, tuỳ thuộc vào cách bạn xem:

<meta name="color-scheme" content="dark light">

Thẻ meta cung cấp tín hiệu sớm nhất có thể, vì vậy, trình duyệt có thể chọn màu canvas mặc định là tối nếu người dùng có lựa chọn ưu tiên về giao diện tối. Điều này có nghĩa là thao tác di chuyển giữa các trang của trang web sẽ không nhấp nháy nền canvas trắng giữa các lần tải. Giao diện tối liền mạch giữa các lần tải, trông đẹp mắt hơn rất nhiều.

Tìm hiểu thêm về Thomas Steiner tại https://web.dev/color-scheme/.

Thêm nội dung

Do cấu trúc nội dung ở trên của ul > li > a > figure > picture > img, nhiệm vụ tiếp theo là thêm hình ảnh và tiêu đề cần cuộn qua. Tôi đã đóng gói bản minh hoạ có văn bản và hình ảnh giữ chỗ tĩnh, nhưng bạn có thể tuỳ ý hỗ trợ tính năng này từ nguồn dữ liệu yêu thích của mình.

Thêm kiểu bằng CSS

Đã đến lúc CSS sử dụng danh sách nội dung chung chung này và biến nó thành một trải nghiệm. Netflix, Cửa hàng ứng dụng cũng như nhiều trang web và ứng dụng khác sử dụng khu vực cuộn ngang để đóng gói khung nhìn với các danh mục và tuỳ chọn.

Tạo bố cục thanh cuộn

Điều quan trọng là cần tránh cắt nội dung trong bố cục hoặc dựa vào việc cắt bớt văn bản bằng dấu ba chấm. Nhiều TV có công cụ cuộn nội dung nghe nhìn giống như thế này, nhưng thường phải dùng đến dấu ba chấm nội dung. Bố cục này thì không! Tính năng này cũng cho phép nội dung nghe nhìn ghi đè kích thước cột, giúp 1 bố cục đủ linh hoạt để xử lý nhiều cách kết hợp thú vị.

2 hàng cuộn hiển thị. Một tiêu đề không có dấu ba chấm, nghĩa là tiêu đề cao hơn và mỗi tiêu đề đều hoàn toàn dễ đọc. Tiêu đề còn lại ngắn hơn và nhiều tiêu đề bị cắt bằng dấu ba chấm.

Vùng chứa cho phép ghi đè kích thước cột bằng cách cung cấp kích thước mặc định dưới dạng thuộc tính tuỳ chỉnh. Bố cục lưới này tập trung vào kích thước cột, chỉ quản lý khoảng cách và hướng:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2); /* parent owned value for children to be relative to*/
  margin: 0;
}

Sau đó, thuộc tính tuỳ chỉnh sẽ được phần tử <picture> sử dụng để tạo tỷ lệ khung hình cơ sở: một hộp:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

Chỉ với một vài kiểu nhỏ nữa, bạn đã có thể hoàn thành phần khung của trình cuộn nội dung đa phương tiện:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  & > li {
    display: inline-block; /* removes the list-item bullet */
  }

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

Việc đặt overflow sẽ thiết lập <ul> để cho phép cuộn và di chuyển bằng bàn phím thông qua danh sách, sau đó mỗi phần tử con <li> trực tiếp sẽ xoá ::marker bằng cách lấy một kiểu hiển thị mới là inline-block.

Tuy nhiên, hình ảnh chưa phản hồi và sẽ bật ra ngay từ hộp bên trong. Sắp xếp chúng bằng một số kiểu kích thước, độ vừa vặn và đường viền, cũng như hiệu ứng chuyển màu cho nền khi tải từng phần:

img {
  /* smash into whatever box it's in */
  inline-size: 100%;
  block-size: 100%;

  /* don't squish but do cover the space */
  object-fit: cover;

  /* soften the edges */
  border-radius: 1ex;
  overflow: hidden;

  /* if empty, show a gradient placeholder */
  background-image:
    linear-gradient(
      to bottom,
      hsl(0 0% 40%),
      hsl(0 0% 20%)
    );
}

Khoảng đệm cuộn

Việc căn chỉnh với nội dung trang và diện tích giao diện cuộn từ cạnh sang cạnh là rất quan trọng đối với một thành phần hài hoà và tối giản.

Để hoàn thành bố cục cuộn từ cạnh này sang cạnh khác phù hợp với kiểu chữ và dòng bố cục, hãy sử dụng padding khớp với scroll-padding:

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block: calc(var(--gap) / 2); /* make space for scrollbar and focus outline */
}

Sửa lỗi khoảng đệm cuộn theo chiều ngang Thông tin trên cho thấy việc đệm vùng chứa cuộn dễ dàng như thế nào, nhưng có một số vấn đề về khả năng tương thích chưa được khắc phục (nhưng đã được khắc phục trong Chromium 91 trở lên!). Vui lòng xem tại đây để biết một số thông tin về lịch sử, nhưng phiên bản ngắn gọn là khoảng đệm không phải lúc nào cũng được tính trong khung hiển thị cuộn.

Một hộp được làm nổi bật ở phía cuối cùng của mục danh sách cuối cùng, hiển thị các khoảng đệm và phần tử có cùng chiều rộng để tạo ra cách căn chỉnh mong muốn.

Để lừa trình duyệt đặt khoảng đệm ở cuối thanh cuộn, tôi sẽ nhắm mục tiêu đến hình cuối cùng trong mỗi danh sách và thêm một phần tử giả tương ứng với số lượng khoảng đệm mong muốn.

.horizontal-media-scroller > li:last-of-type figure {
  position: relative;

  &::after {
    content: "";
    position: absolute;

    inline-size: var(--gap);
    block-size: 100%;

    inset-block-start: 0;
    inset-inline-end: calc(var(--gap) * -1);
  }
}

Việc sử dụng các thuộc tính logic cho phép trình cuộn nội dung nghe nhìn hoạt động ở mọi chế độ ghi và hướng tài liệu.

Chụp ảnh khi cuộn

Vùng chứa cuộn có tràn có thể trở thành khung nhìn chụp nhanh với một dòng CSS, sau đó, phần tử con chỉ định cách chúng muốn căn chỉnh với khung nhìn đó.

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block-end: calc(var(--gap) / 2);

  scroll-snap-type: inline mandatory;

  & figure {
    scroll-snap-align: start;
  }
}

Trọng tâm

Cảm hứng cho thành phần này bắt nguồn từ sự phổ biến cực lớn của nó trên TV, trong Cửa hàng ứng dụng và nhiều nơi khác. Nhiều nền tảng trò chơi điện tử sử dụng công cụ cuộn nội dung nghe nhìn rất giống với công cụ này để làm bố cục màn hình chính chính. Trọng tâm là một khoảnh khắc trải nghiệm người dùng rất lớn ở đây, không chỉ là một bổ sung nhỏ. Hãy tưởng tượng bạn dùng công cụ cuộn nội dung đa phương tiện này trên chiếc ghế dài của bạn bằng một chiếc điều khiển từ xa để thực hiện một số tính năng nâng cao nhỏ cho hoạt động tương tác đó:

.horizontal-media-scroller a {
  outline-offset: 12px;

  &:focus {
    outline-offset: 7px;
  }

  @media (prefers-reduced-motion: no-preference) {
    & {
      transition: outline-offset .25s ease;
    }
  }
}

Thao tác này sẽ đặt kiểu đường viền tiêu điểm 7px cách xa hộp, mang lại cho giao diện một không gian đẹp mắt. Nếu người dùng không ưu tiên chuyển động liên quan đến việc giảm chuyển động, thì độ lệch sẽ được chuyển đổi, tạo ra chuyển động tinh tế cho sự kiện lấy tiêu điểm.

Chỉ số lưu động

Người dùng tay điều khiển trò chơi và bàn phím cần đặc biệt chú ý đến các danh sách dài gồm các tuỳ chọn và nội dung cuộn. Mô hình phổ biến để giải quyết vấn đề này được gọi là chỉ mục lưu động. Đó là khi một vùng chứa các mục được lấy làm tâm điểm bằng bàn phím nhưng chỉ có 1 thành phần con được phép giữ tâm điểm tại một thời điểm. Một mục có thể làm tâm điểm này tại một thời điểm được thiết kế để cho phép bỏ qua danh sách mục có thể dài, thay vì nhấn thẻ hơn 50 lần để đến cuối.

Có 300 mục trong thanh cuộn đầu tiên của bản minh hoạ. Chúng ta có thể làm tốt hơn là khiến chúng chuyển qua tất cả các phần tử để đến phần tiếp theo.

Để tạo trải nghiệm này, JavaScript cần quan sát các sự kiện bàn phím và sự kiện tiêu điểm. Tôi đã tạo một thư viện nguồn mở nhỏ trên npm để giúp dễ dàng đạt được trải nghiệm người dùng này. Dưới đây là cách sử dụng trường này cho 3 thanh cuộn:

import {rovingIndex} from 'roving-ux';

rovingIndex({
  element: someElement
});

Bản minh hoạ này truy vấn tài liệu cho các thanh cuộn và gọi hàm rovingIndex() cho mỗi thanh cuộn. Truyền phần tử rovingIndex() để có được trải nghiệm lưu động, như vùng chứa danh sách và bộ chọn truy vấn mục tiêu, trong trường hợp các mục tiêu lấy nét không phải là thành phần con trực tiếp.

document.querySelectorAll('.horizontal-media-scroller')
  .forEach(scroller =>
    rovingIndex({
      element: scroller,
      target: 'a',
}))

Để tìm hiểu thêm về hiệu ứng này, hãy xem thư viện nguồn mở roving-ux.

Tỷ lệ khung hình

Khi viết bài đăng này, tính năng hỗ trợ dành cho aspect-ratio đã có sau một cờ trong Firefox nhưng có sẵn trong trình duyệt Chromium hoặc hộp giải mã tín hiệu số. Vì bố cục lưới của trình cuộn nội dung đa phương tiện chỉ xác định hướng và khoảng cách, nên kích thước có thể thay đổi bên trong truy vấn nội dung đa phương tiện giúp kiểm tra khả năng hỗ trợ tỷ lệ khung hình. Nâng cao dần dần thành một số trình cuộn nội dung nghe nhìn linh động hơn.

Hộp có tỷ lệ khung hình 4:4 sẽ xuất hiện bên cạnh các tỷ lệ thiết kế khác (sử dụng tỷ lệ 16:9 và 4:3)

@supports (aspect-ratio: 1) {
  .horizontal-media-scroller figure > picture {
    inline-size: auto; /* for a block-size driven ratio */
    aspect-ratio: 1; /* boxes by default */

    @nest section:nth-child(2) & {
      aspect-ratio: 16/9;
    }

    @nest section:nth-child(3) & {
      /* double the size of the others */
      block-size: calc(var(--size) * 2);
      aspect-ratio: 4/3;

      /* adjust size to fit more items into the viewport */
      @media (width <= 480px) {
        block-size: calc(var(--size) * 1.5);
      }
    }
  }
}

Nếu trình duyệt hỗ trợ cú pháp aspect-ratio, thì hình ảnh trong công cụ cuộn nội dung đa phương tiện sẽ được nâng cấp lên kích thước aspect-ratio. Khi sử dụng cú pháp lồng nhau của bản nháp, mỗi hình ảnh sẽ thay đổi tỷ lệ khung hình tuỳ thuộc vào việc đó là hàng đầu tiên, thứ hai hay thứ ba. Cú pháp lồng cũng cho phép thiết lập một số điều chỉnh nhỏ đối với khung nhìn, ngay tại đó cùng với logic định kích thước khác.

Với CSS đó, vì tính năng này có trong nhiều công cụ trình duyệt hơn, nên một bố cục dễ quản lý nhưng hấp dẫn hơn về mặt hình ảnh sẽ hiển thị.

Ưu tiên dữ liệu giảm

Mặc dù kỹ thuật tiếp theo này chỉ có sẵn phía sau cờ trong Canary, nhưng tôi muốn chia sẻ cách tôi có thể tiết kiệm đáng kể thời gian tải trang và sử dụng dữ liệu thông qua một vài dòng CSS. Truy vấn nội dung nghe nhìn prefers-reduced-data từ cấp 5 cho phép hỏi xem thiết bị có đang ở bất kỳ trạng thái dữ liệu được giảm nào hay không, chẳng hạn như chế độ tiết kiệm dữ liệu. Nếu được, tôi có thể sửa đổi tài liệu và trong trường hợp này là ẩn hình ảnh.

ALT_TEXT_HERE

figure {
  @media (prefers-reduced-data: reduce) {
    & {
      min-inline-size: var(--size);

      & > picture {
        display: none;
      }
    }
  }
}

Bạn vẫn có thể di chuyển trong nội dung này mà không phải tải các hình ảnh nặng xuống. Dưới đây là trang web trước khi thêm CSS prefers-reduced-data:

(7 yêu cầu, 100 kb tài nguyên trong 131 mili giây)

ALT_TEXT_HERE

Dưới đây là hiệu suất của trang web sau khi thêm CSS prefers-reduced-data:

ALT_TEXT_HERE

(71 yêu cầu, 1,2mb tài nguyên trong 1,07 giây)

Giảm 64 yêu cầu, đó là khoảng 60 hình ảnh trong khung nhìn (các phép kiểm thử được chụp trên màn hình rộng) của thẻ trình duyệt này, mức tăng tải trang xấp xỉ 80% và 10% dữ liệu qua dây. CSS khá mạnh.

Kết luận

Giờ bạn đã biết tôi làm việc đó như thế nào, bạn sẽ làm thế nào?! 🙂

Hãy đa dạng hoá phương pháp tiếp cận của chúng ta và tìm hiểu tất cả các cách xây dựng trên web. Tạo Codepen hoặc tổ chức bản minh hoạ của riêng bạn, đăng bài cho tôi trên Twitter và tôi sẽ thêm vào phần Bản phối lại của cộng đồng bên dưới.

Nguồn

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

Chưa có nội dung nào để xem ở đây!