Tổng quan cơ bản về cách tạo thành phần hiển thị 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ác cách tạo trải nghiệm cuộn ngang cho web sao cho tối giản, thích ứng, dễ tiếp cận và hoạt động trên các trình duyệt và nền tảng (như TV!). Hãy dùng thử bản minh hoạ.
Nếu bạn thích xem video, hãy xem phiên bản video của bài đăng này trên YouTube:
Tổng quan
Chúng ta sẽ xây dựng một bố cục cuộn ngang để 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 này bắt đầu là một danh sách <ul>
đơn giản nhưng được chuyển đổi bằng CSS thành trải nghiệm cuộn mượt mà và hài lòng, hiển thị hình ảnh và chụp nhanh các hình ảnh đó vào 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 chuyển, giúp người dùng bàn phím bỏ qua việc di chuyển qua hơn 100 mục.
Ngoài ra, một truy vấn nội dung nghe nhìn thử nghiệm, prefers-reduced-data
, được dùng để biến thanh cuộn nội dung nghe nhìn thành trải nghiệm thanh cuộn tiêu đề gọn nhẹ.
Bắt đầu với mã đánh dấu hỗ trợ tiếp cận
Trình cuộn nội dung nghe nhìn chỉ bao gồm một vài thành phần cốt lõi, một danh sách có các mục. Ở dạng đơn giản nhất, danh sách có thể đi du lịch vòng quanh thế giới và rõ ràng được tất cả mọi người thưởng thứ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ặt hàng. Đây là cơ sở hỗ trợ tiếp cận của chúng tôi.
Phân phối danh sách có phần tử <ul>
:
<ul class="horizontal-media-scroller">
<li></li>
<li></li>
<li></li>
...
<ul>
Tạo các mục trong danh sách có thể tương tác 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>
Lưu ý các thuộc tính alt
và loading
trên <img>
. Văn bản thay thế cho thanh cuộn nội dung nghe nhìn là một cơ hội về trải nghiệm người dùng để giúp cung cấp thêm ngữ cảnh cho hình thu nhỏ hoặc làm 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 lời nói cho những 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 qua bài viết 5 quy tắc vàng để đảm bảo 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
để báo hiệu rằng nguồn hình ảnh này chỉ được tìm nạp khi hình ảnh nằm trong khung nhìn. Điều này có thể rất hữu ích đối 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 mà họ đã 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>
để báo hiệu cho trình duyệt rằng trang của bạn muốn có cả kiểu tác nhân người dùng sáng và tối. Đây 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 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à các thao tác điều hướng giữa các trang của trang web sẽ không hiển thị 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, dễ nhìn hơn nhiều.
Tìm hiểu thêm 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 đã đóng gói bản minh hoạ bằng hình ảnh và văn bản giữ chỗ tĩnh, nhưng bạn có thể sử dụng nguồn dữ liệu yêu thích của mình.
Thêm kiểu bằng CSS
Giờ là lúc CSS lấy danh sách nội dung chung này và biến nó thành một trải nghiệm. Netflix, Cửa hàng ứng dụng và nhiều trang web và ứng dụng khác sử dụng các khu vực cuộn ngang để đóng gói khung nhìn bằng các danh mục và tuỳ chọn.
Tạo bố cục thanh cuộn
Điều quan trọng là bạn phải tránh cắt nội dung trong bố cục hoặc cắt bớt văn bản bằng dấu ba chấm. Nhiều TV có trình cuộn nội dung đa phương tiện giống như trình cuộn này, nhưng thường xuyên sử dụng tính năng cắt bớt nội dung. Bố cục này không! Tính năng này cũng cho phép nội dung đa phương tiện ghi đè kích thước cột, giúp 1 bố cục linh hoạt để xử lý nhiều tổ hợp thú vị.
Vùng chứa này 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 có ý kiến 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ẽ 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ỉ cần thêm một vài kiểu nhỏ nữa, bạn đã hoàn tất phần cơ bản của thanh cuộn nội dung nghe 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;
& > li {
display: inline-block; /* removes the list-item bullet */
}
& picture {
inline-size: var(--size);
block-size: var(--size);
}
}
Việc thiết lập overflow
sẽ thiết lập <ul>
để cho phép cuộn và điều hướng bằng bàn phím thông qua danh sách, sau đó mỗi phần tử <li>
con trực tiếp sẽ bị xoá ::marker
bằng cách lấy loại hiển thị mới là inline-block
.
Tuy nhiên, các hình ảnh chưa thích ứng và bị tràn ra khỏi hộp chứa. Hãy điều chỉnh các thành phần này bằng một số kích thước, kiểu dáng vừa vặn và đường viền, cũng như một hiệu ứng chuyển màu nền khi chúng đang tải lười:
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, cùng với khu vực cuộn từ cạnh này sang cạnh kia, là yếu tố quan trọng để tạo ra một thành phần hài hòa và tối giản.
Để hoàn thành bố cục cuộn từ cạnh này sang cạnh kia, căn chỉnh với kiểu chữ và các 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 Phần trên cho thấy việc thêm khoảng đệm cho vùng chứa cuộn rất dễ dàng, nhưng vẫn có các vấn đề về khả năng tương thích với vùng chứa này (mặc dù đã được khắc phục trong Chromium 91 trở lên!). Hãy xem nội dung tại đây để biết một chút về quá trình phát triển, nhưng tóm lại là khoảng đệm không phải lúc nào cũng được tính đến trong thành phần hiển thị cuộn.
Để lừa trình duyệt đặt khoảng đệm ở cuối thanh cuộn, tôi sẽ nhắm đến hình cuối cùng trong mỗi danh sách và thêm một phần tử giả là 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 thanh cuộn nội dung nghe nhìn hoạt động ở bất kỳ chế độ ghi nào và hướng tài liệu.
Cố định vị trí cuộn
Vùng chứa cuộn có vùng tràn có thể trở thành khung nhìn chụp nhanh bằng một dòng CSS, sau đó, các phần tử con sẽ 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ừ sự phổ biến rộng rãi của thành phần này 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 thanh cuộn nội dung nghe nhìn rất giống với thanh cuộn này làm bố cục màn hình chính chính. Tiêu điểm là một khoảnh khắc trải nghiệm người dùng rất quan trọng, chứ không chỉ là một điểm bổ sung nhỏ. Hãy tưởng tượng bạn sử dụng thanh cuộn nội dung nghe nhìn này trên ghế sofa bằng điều khiển từ xa, hãy cung cấp một số điểm cải tiến 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
ra khỏi hộp, tạo ra một khoảng trống đẹp mắt. Nếu người dùng không có lựa chọn ưu tiên về chuyển động để giảm chuyển động, thì độ dời sẽ được chuyển đổi, tạo chuyển động nhẹ nhàng cho sự kiện lấy tiêu điểm.
Chỉ mục di chuyển
Người dùng tay điều khiển trò chơi và bàn phím cần được chú ý đặc biệt trong các danh sách dài này về nội dung và tuỳ chọn cuộn. Mẫu phổ biến để giải quyết vấn đề này được gọi là chỉ mục lưu động (rovingindex). Đó là khi một vùng chứa các mục được lấy tiêu điểm bằng bàn phím nhưng mỗi lần chỉ cho phép 1 phần tử con giữ tiêu điểm. Mục duy nhất có thể làm tâm điể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 phím tab hơn 50 lần để xem hết.
Có 300 mục trong trình cuộn đầu tiên của bản minh hoạ. Chúng ta có thể làm tốt hơn là làm cho chúng duyệt qua tất cả chúng để đế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 tâm điểm. Tôi đã tạo một thư viện nguồn mở nhỏ trên npm để giúp người dùng dễ dàng đạt được trải nghiệm này. Sau đây là cách sử dụng nó 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à cho mỗi thanh cuộn, gọi hàm rovingIndex()
. Truyền phần tử rovingIndex()
để có được trải nghiệm lưu động, chẳng hạ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 các mục tiêu tâm điểm không phải là thành phần con cháu 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 này, tính năng hỗ trợ aspect-ratio
đang ở trạng thái bật trong Firefox nhưng có trong trình duyệt Chromium hoặc hộp set-top. Vì bố cục lưới của thanh cuộn nội dung nghe nhìn chỉ chỉ đị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 nghe nhìn có tính năng kiểm tra khả năng hỗ trợ tỷ lệ khung hình.
Cải tiến dần vào một số trình cuộn nội dung nghe nhìn linh động hơn.
@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ì ảnh của trình 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 bản nháp, mỗi bức ảnh sẽ thay đổi tỷ lệ khung hình tuỳ thuộc vào việc đó là hàng đầu, hàng thứ hai hay hàng 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 đó với logic định cỡ khác.
Với CSS đó, vì tính năng này có sẵn trong nhiều công cụ trình duyệt hơn nên sẽ hiển thị một bố cục dễ quản lý nhưng bắt mắt hơn.
Ưu tiên giảm dữ liệu
Mặc dù kỹ thuật tiếp theo này chỉ có sẵn dưới dạng cờ trong Canary, nhưng tôi muốn chia sẻ cách tiết kiệm đáng kể thời gian tải trang và mức sử dụng dữ liệu bằng 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ó ở trạng thái giảm dữ liệu nào 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, ẩn hình ảnh.
figure {
@media (prefers-reduced-data: reduce) {
& {
min-inline-size: var(--size);
& > picture {
display: none;
}
}
}
}
Người dùng vẫn có thể xem nội dung mà không phải tốn chi phí 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)
Sau đây là hiệu suất của trang web sau khi thêm CSS prefers-reduced-data
:
(71 yêu cầu, 1,2 MB tài nguyên trong 1,07 giây)
Giảm 64 yêu cầu, tức là khoảng 60 hình ảnh trong khung nhìn (các thử nghiệm được thực hiện trên màn hình rộng) của thẻ trình duyệt này, tăng tốc độ tải trang khoảng 80% và 10% dữ liệu qua mạng. CSS khá mạnh mẽ.
Kết luận
Giờ thì bạn đã biết cách tôi làm, còn bạn thì sao?! 🙂
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 Codepen hoặc lưu trữ bản minh hoạ của riêng bạn, tweet cho tôi về bản minh hoạ đó và tôi sẽ thêm bản minh hoạ đó 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!