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

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ẻ cách tạo cuộn ngang cho web ở mức tối thiểu, phản hồi nhanh, dễ truy cập và hoạt động trên trình duyệt và nền tảng (như TV chẳng hạn!). Dùng thử bản minh hoạ.

Bản minh hoạ

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

Tổng quan

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

Bắt đầu bằng mã đánh dấu dễ tiếp cận

Một trình cuộn nội dung đa phương tiện chỉ được tạo từ hai thành phần cốt lõi, là một danh sách chứa các mục. Đáp danh sách, ở dạng đơn giản nhất, có thể đi du lịch vòng quanh thế giới và được tiêu thụ bởi tất cả. Người dùng truy cập vào trang này có thể duyệt xem danh sách và nhấp vào đường liên kết để xem một mục. Đây là cơ sở dễ 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 của hình ảnh theo 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 ý các thuộc tính altloading trên <img>. Văn bản thay thế cho nội dung nghe nhìn Công cụ cuộn là một cơ hội trải nghiệm người dùng, giúp cung cấp thêm bối cảnh cho hình thu nhỏ hoặc 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 bằng giọng nói cho người dùng dựa vào công nghệ hỗ trợ như trình đọc màn hình. Tìm hiểu thêm với Five Golden quy tắc cho ngôn ngữ thay thế tuân thủ văn bản.

Thuộc tính loading chấp nhận từ khoá lazy làm cách để truyền tín hiệu về hình ảnh này nguồn chỉ nên được tìm nạp khi hình ảnh nằm trong khung nhìn. Thông tin này có thể là thực sự phù hợp với các danh sách lớn, vì người dùng sẽ chỉ tải hình ảnh xuống cho các mục họ mà người dùng đã cuộn vào chế độ xem.

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

Sử dụng color-scheme làm thẻ <meta> để trình duyệt biết rằng trang của bạn muốn có cả kiểu sáng và tối do tác nhân người dùng cung cấp. Bạn đang dùng chế độ tối miễn phí hoặc chế độ sáng, tuỳ theo 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ể, để trình duyệt có thể chọn màu tối cho canvas mặc định nếu người dùng có giao diện tối ưu tiên. Tức là thao tác điều hướng giữa các trang trên trang web sẽ không nhấp nháy canvas màu trắng nền 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, đẹp hơn nhiều trên mắt.

Tìm hiểu thêm nhiều từ 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 đề để cuộn qua. Tôi đã chuẩn bị bản minh hoạ hình ảnh và văn bản giữ chỗ tĩnh, nhưng bạn có thể sử dụng tính năng này nguồn dữ liệu ưa thích của bạn.

Thêm kiểu bằng CSS

Giờ là lúc CSS sử dụng danh sách nội dung chung này và biến nó thành một của bạn. Netflix, App Store cũng như nhiều trang web và ứng dụng khác sử dụng định dạng ngang các khu vực cuộn để đóng gói khung nhìn với các danh mục và tuỳ chọn.

Tạo bố cục trình cuộn

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

2
hàng cuộn được hiển thị. Một hình ảnh không có dấu ba chấm, có nghĩa là hình ảnh đó cao hơn và mỗi dấu chấm câu sẽ cao hơn
tiê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ớt
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 như một thuộc tính tuỳ chỉnh. Bố cục lưới này quy định về 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 đó, phần tử <picture> sử dụng thuộc tính tuỳ chỉnh này để 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, hãy hoàn thiện phần cơ bản 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 thao tác cuộn và di chuyển bằng bàn phím thông qua danh sách, thì mỗi phần tử con <li> trực tiếp sẽ bị xoá ::marker bằng cách tải kiểu hiển thị mới là inline-block.

Tuy nhiên, hình ảnh chưa phản hồi và nhanh chóng thoát ra khỏi hộp chúng đang ở bên trong. Hãy điều chỉnh chúng bằng một số kích thước, kiểu dáng và kiểu đường viền, cũng như hiệu ứng chuyển màu 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

Căn chỉnh với nội dung trang, cộng với diện tích giao diện cuộn từ cạnh này sang cạnh khác quan trọng đối với thành phần hài hoà và tối giản.

Để hoàn thành bố cục cuộn tràn viền cho phù hợp với kiểu chữ của chúng tôi 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 Nội dung trên cho thấy mức độ dễ dàng thêm một vùng chứa cuộn, nhưng có một số vấn đề chưa được giải quyết về khả năng tương thích (đã khắc phục trong Chromium 91 trở lên!). Xem tại đây một chút của 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 đến trong chế độ xem cuộn.

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

Để lừa trình duyệt đặt khoảng đệm ở cuối trình cuộn, tôi sẽ nhắm mục tiêu hình cuối cùng trong mỗi danh sách và thêm một phần tử giả 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/Cuộn

Vùng chứa cuộn có mục bổ sung có thể trở thành khung nhìn chụp nhanh với một dòng CSS, sau đó phần tử con phải 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;
  }
}

Tập trung

Cảm hứng cho thành phần này đến từ việc nó rất phổ biến trên TV, trong App Store và nhiều cửa hàng khác. Nhiều nền tảng trò chơi điện tử sử dụng trình cuộn nội dung đa phương tiện tương tự như bố cục này, làm bố cục màn hình chính chính. Tập trung là trải nghiệm người dùng lớn không chỉ là một bổ sung nhỏ. Hãy tưởng tượng dùng trình cuộn nội dung nghe nhìn này từ chiếc ghế dài của bạn bằng điều khiển từ xa, hãy cải thiện một số chi tiết 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, tạo cho nó một chút . Nếu người dùng không có ưu tiên chuyển động về việc giảm chuyển động, thì độ lệch được chuyển tiếp, tạo ra chuyển động tinh tế cho sự kiện 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ú ý trong các danh sách dài này cuộn nội dung và tuỳ chọn. Mô hình chung để giải quyết vấn đề này được gọi là chỉ mục lưu hành. Đó là khi 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ỉ 1 thành phần con được phép giữ tiêu điểm cùng một lúc. Mục có thể lấy làm tâm điểm duy nhất này tại một trải nghiệm tại một thời điểm được thiết kế để cho phép bỏ qua danh sách các mục có thể dài, thay vì nhấn thẻ 50+ lần để kết thúc.

Có 300 mục trong trình cuộn đầu tiên của bản minh hoạ. Chúng tôi có thể làm tốt hơn là chuyển tải tất cả các tệp đó để đế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à tiêu điểm các sự kiện. Tôi đã tạo một thư viện nguồn mở nhỏ trên npm để giúp người dùng này dễ dàng đạt được. Dưới đây là cách sử dụng trình cuộn cho 3 trình 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 trình cuộn và cho mỗi trình cuộn gọi hàm Hàm rovingIndex(). Truyền phần tử rovingIndex() để di chuyển như vùng chứa danh sách và bộ chọn truy vấn mục tiêu, trong trường hợp mục tiêu tâm điểm 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

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

Đáp
có tỷ lệ khung hình 4:4 được hiển thị bên cạnh các tỷ lệ thiết kế khác được sử dụng 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 của trình cuộn nội dung nghe nhìn sẽ đã nâng cấp lên kích thước aspect-ratio. Sử dụng cú pháp lồng bản nháp, mỗi hình ảnh thay đổi tỷ lệ khung hình tuỳ theo việc đó là hàng đầu tiên, thứ hai hay thứ ba. Chiến lược phát hành đĩa đơn cú pháp Nest cũng cho phép đặt một số điều chỉnh khung nhìn, ngay ở đó với logic định kích thước khác.

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

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

Mặc dù kỹ thuật tiếp theo này chỉ có sẵn phía sau một lá cờCanary, 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 phương tiệ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 giảm nào, 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, hãy ẩn hình ảnh.

ALT_TEXT_HERE

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

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

Nội dung vẫn có thể điều hướng được mà không phải trả chi phí cho việc sử dụng các hình ảnh quá lớn đã tải xuống. Đây là trang web trước khi thêm CSS prefers-reduced-data:

(7 yêu cầu, 100kb 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,2 MB tài nguyên trong 1,07 giây)

Ít hơn 64 yêu cầu, tức là khoảng 60 hình ảnh trong khung nhìn (các thử nghiệm đã thực hiện trên màn hình rộng) của thẻ trình duyệt này, tăng tải trang khoảng 80% và 10% dữ liệu qua mạng. CSS khá mạnh mẽ.

Kết luận

Giờ bạn đã biết cách tôi thực hiện điều đó, bạn sẽ làm thế nào?! 🙂

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

Nguồn

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

Chưa có gì để xem ở đây!