Tìm hiểu cách sử dụng Dòng thời gian cuộn và Dòng thời gian của khung hiển thị để tạo ảnh động dựa trên thao tác cuộn theo cách khai báo.
Xuất bản: Ngày 5 tháng 5 năm 2023
Ảnh động dựa trên thao tác cuộn
Ảnh động dựa trên thao tác cuộn là một mẫu trải nghiệm người dùng phổ biến trên web. Ảnh động dựa trên thao tác cuộn được liên kết với vị trí cuộn của một vùng chứa có thể cuộn. Điều này có nghĩa là khi bạn cuộn lên hoặc xuống, ảnh động được liên kết sẽ tua đi hoặc tua lại để phản hồi trực tiếp. Ví dụ: hiệu ứng như hình nền thị sai hoặc chỉ báo đọc di chuyển khi bạn cuộn.
Một loại ảnh động dựa trên thao tác cuộn tương tự là ảnh động được liên kết với vị trí của một phần tử trong vùng chứa có thể cuộn. Ví dụ: nhờ đó, các phần tử có thể xuất hiện dần khi hiển thị.
Cách truyền thống để đạt được những hiệu ứng này là phản hồi các sự kiện cuộn trên luồng chính, dẫn đến 2 vấn đề chính:
- Các trình duyệt hiện đại thực hiện thao tác cuộn trên một quy trình riêng biệt và do đó, cung cấp các sự kiện cuộn không đồng bộ.
- Ảnh động trên luồng chính dễ bị giật.
Điều này khiến việc tạo ảnh động dựa trên thao tác cuộn có hiệu suất cao và đồng bộ với thao tác cuộn trở nên bất khả thi hoặc rất khó thực hiện.
Kể từ Chrome phiên bản 115, có một bộ API và khái niệm mới mà bạn có thể sử dụng để bật các hiệu ứng chuyển động dựa trên thao tác cuộn theo cách khai báo: Dòng thời gian cuộn và Dòng thời gian xem.
Những khái niệm mới này tích hợp với Web Animations API (WAAPI) và CSS Animations API hiện có, cho phép chúng kế thừa những lợi thế mà các API hiện có này mang lại. Điều này bao gồm cả khả năng chạy ảnh động dựa trên thao tác cuộn ở ngoài luồng chính. Đúng vậy, bạn không nghe nhầm đâu: giờ đây, bạn có thể tạo ảnh động mượt mà, được điều khiển bằng thao tác cuộn, chạy trên luồng chính chỉ với vài dòng mã bổ sung. Bạn không thích điều gì?!
Ảnh động trên web, một bản tóm tắt ngắn
Ảnh động trên web bằng CSS
Để tạo một ảnh động trong CSS, hãy xác định một tập hợp khung hình chính bằng cách sử dụng quy tắc @keyframes. Liên kết đối tượng này với một phần tử bằng cách sử dụng thuộc tính animation-name, đồng thời đặt animation-duration để xác định thời lượng của ảnh động. Có nhiều thuộc tính animation-* dài hơn – animation-easing-function và animation-fill-mode chỉ là một vài ví dụ – tất cả đều có thể kết hợp trong thuộc tính animation viết tắt.
Ví dụ: sau đây là một ảnh động giúp tăng tỷ lệ một phần tử trên trục X, đồng thời thay đổi màu nền của phần tử đó:
@keyframes scale-up {
from {
background-color: red;
transform: scaleX(0);
}
to {
background-color: darkred;
transform: scaleX(1);
}
}
#progressbar {
animation: 2.5s linear forwards scale-up;
}
Ảnh động trên web bằng JavaScript
Trong JavaScript, bạn có thể sử dụng Web Animations API để đạt được kết quả tương tự. Bạn có thể thực hiện việc này bằng cách tạo các thực thể Animation và KeyFrameEffect mới hoặc sử dụng phương thức Element animate() ngắn hơn nhiều.
document.querySelector('#progressbar').animate(
{
backgroundColor: ['red', 'darkred'],
transform: ['scaleX(0)', 'scaleX(1)'],
},
{
duration: 2500,
fill: 'forwards',
easing: 'linear',
}
);
Kết quả trực quan của đoạn mã JavaScript ở trên giống hệt với phiên bản CSS trước đó.
Dòng thời gian của ảnh động
Theo mặc định, ảnh động được đính kèm vào một phần tử sẽ chạy trên dòng thời gian của tài liệu. Thời gian bắt đầu của chỉ số này là 0 khi trang tải và bắt đầu tăng lên khi thời gian trôi qua. Đây là dòng thời gian mặc định của ảnh động và cho đến nay, đây là dòng thời gian duy nhất của ảnh động mà bạn có quyền truy cập.
Quy cách ảnh động dựa trên thao tác cuộn xác định 2 loại dòng thời gian mới mà bạn có thể sử dụng:
- Dòng thời gian tiến trình cuộn: dòng thời gian được liên kết với vị trí cuộn của một vùng chứa có thể cuộn dọc theo một trục cụ thể.
- Xem dòng thời gian tiến trình: một dòng thời gian được liên kết với vị trí tương đối của một phần tử cụ thể trong vùng chứa có thể cuộn.
Thanh tiến trình cuộn
Dòng thời gian tiến trình cuộn là một dòng thời gian ảnh động được liên kết với tiến trình ở vị trí cuộn của một vùng chứa có thể cuộn (còn gọi là scrollport hoặc scroller) dọc theo một trục cụ thể. Thao tác này chuyển đổi một vị trí trong phạm vi cuộn thành tỷ lệ phần trăm tiến trình.
Vị trí bắt đầu cuộn biểu thị tiến trình 0% và vị trí kết thúc cuộn biểu thị tiến trình 100%. Trong hình ảnh trực quan sau đây, bạn có thể thấy tiến trình tăng từ 0% đến 100% khi bạn di chuyển thanh cuộn từ trên xuống dưới.
✨ Hãy tự mình dùng thử
Dòng thời gian tiến trình cuộn thường được viết tắt thành "Dòng thời gian cuộn".
Xem Dòng thời gian tiến trình
Loại tiến trình này được liên kết với tiến trình tương đối của một phần tử cụ thể trong vùng chứa có thể cuộn. Giống như Dòng thời gian tiến trình cuộn, độ lệch cuộn của trình cuộn cũng được theo dõi. Không giống như Dòng thời gian tiến trình cuộn, vị trí tương đối của một đối tượng trong thành phần có thể cuộn đó sẽ xác định tiến trình.
Điều này có phần tương tự như cách hoạt động của IntersectionObserver, có thể theo dõi mức độ hiển thị của một phần tử trong trình cuộn. Nếu phần tử không xuất hiện trong trình cuộn, thì phần tử đó sẽ không giao nhau. Nếu phần tử đó xuất hiện bên trong trình cuộn (ngay cả đối với phần nhỏ nhất), thì phần tử đó đang giao nhau.
Dòng thời gian tiến trình xem bắt đầu từ thời điểm một đối tượng bắt đầu giao nhau với thành phần cuộn và kết thúc khi đối tượng đó ngừng giao nhau với thành phần cuộn. Trong hình ảnh trực quan sau đây, bạn có thể thấy rằng tiến trình bắt đầu đếm từ 0% khi đối tượng nhập vùng chứa có thể di chuyển và đạt 100% ngay khi đối tượng rời khỏi vùng chứa có thể di chuyển.
✨ Hãy tự mình dùng thử
Dòng thời gian tiến trình xem thường được gọi đơn giản là "Dòng thời gian xem". Bạn có thể nhắm đến các phần cụ thể của Dòng thời gian xem dựa trên kích thước của đối tượng, nhưng chúng ta sẽ nói về vấn đề này sau.
Thực hành với Dòng thời gian tiến trình cuộn
Tạo Dòng thời gian tiến trình cuộn ẩn danh trong CSS
Cách dễ nhất để tạo một Dòng thời gian cuộn trong CSS là sử dụng hàm scroll(). Thao tác này sẽ tạo một Scroll Timeline ẩn danh mà bạn có thể đặt làm giá trị cho thuộc tính animation-timeline mới.
Ví dụ:
@keyframes animate-it { … }
.subject {
animation: animate-it linear;
animation-timeline: scroll(root block);
}
Hàm scroll() chấp nhận một đối số <scroller> và một đối số <axis>.
Các giá trị được chấp nhận cho đối số <scroller> là:
nearest: Sử dụng vùng chứa cuộn tổ tiên gần nhất (mặc định).root: Sử dụng khung hiển thị tài liệu làm vùng chứa cuộn.self: Sử dụng chính phần tử này làm vùng chứa có thể cuộn.
Các giá trị được chấp nhận cho đối số <axis> là:
block: Sử dụng thước đo tiến trình dọc theo trục khối của vùng chứa có thể cuộn (mặc định).inline: Sử dụng thước đo tiến trình dọc theo trục nội tuyến của vùng chứa có thể cuộn.y: Sử dụng chỉ số tiến trình dọc theo trục y của vùng chứa có thể cuộn.x: Sử dụng chỉ số tiến trình dọc theo trục x của vùng chứa có thể cuộn.
Ví dụ: để liên kết một ảnh động với trình cuộn gốc trên trục khối, các giá trị cần truyền vào scroll() là root và block. Tổng giá trị là scroll(root block).
Bản minh hoạ: Chỉ báo tiến trình đọc
Bản minh hoạ này có một chỉ báo tiến trình đọc được cố định ở đầu khung nhìn. Khi bạn cuộn xuống trang, thanh tiến trình sẽ tăng lên cho đến khi chiếm toàn bộ chiều rộng của khung hiển thị khi bạn đến cuối tài liệu. Dòng thời gian tiến trình cuộn ẩn danh được dùng để điều khiển ảnh động.
✨ Hãy tự mình dùng thử
Chỉ báo tiến trình đọc được đặt ở đầu trang bằng cách sử dụng vị trí cố định. Để tận dụng ảnh động kết hợp, không phải width đang được tạo hiệu ứng động mà phần tử được thu nhỏ trên trục x bằng cách dùng transform.
<body>
<div id="progress"></div>
…
</body>
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
#progress {
position: fixed;
left: 0; top: 0;
width: 100%; height: 1em;
background: red;
transform-origin: 0 50%;
animation: grow-progress auto linear;
animation-timeline: scroll();
}
Dòng thời gian cho ảnh động grow-progress trên phần tử #progress được đặt thành một dòng thời gian ẩn danh được tạo bằng scroll(). Không có đối số nào được đưa ra cho scroll(), vì vậy, đối số này sẽ quay về các giá trị mặc định.
Trình cuộn mặc định cần theo dõi là nearest và trục mặc định là block. Thao tác này nhắm đến trình cuộn gốc một cách hiệu quả vì đó là trình cuộn gần nhất của phần tử #progress, đồng thời theo dõi hướng khối của trình cuộn đó.
Tạo Dòng thời gian tiến trình cuộn có tên trong CSS
Một cách khác để xác định Dòng thời gian tiến trình cuộn là sử dụng một dòng thời gian có tên. Cách này có phần dài dòng hơn, nhưng có thể hữu ích khi bạn không nhắm đến một thành phần cuộn mẹ hoặc thành phần cuộn gốc, hoặc khi trang sử dụng nhiều dòng thời gian hoặc khi tính năng tra cứu tự động không hoạt động. Bằng cách này, bạn có thể xác định một Dòng thời gian tiến trình cuộn theo tên mà bạn đặt cho dòng thời gian đó.
Để tạo một Dòng thời gian tiến trình cuộn có tên trên một phần tử, hãy đặt thuộc tính scroll-timeline-name CSS trên vùng chứa cuộn thành một giá trị nhận dạng mà bạn thích. Giá trị phải bắt đầu bằng --.
Để điều chỉnh trục cần theo dõi, hãy khai báo thuộc tính scroll-timeline-axis. Các giá trị được phép giống với đối số <axis> của scroll().
Cuối cùng, để liên kết ảnh động với Dòng thời gian tiến trình cuộn, hãy đặt thuộc tính animation-timeline trên phần tử cần tạo ảnh động thành cùng giá trị với giá trị nhận dạng được dùng cho scroll-timeline-name.
Ví dụ về mã:
@keyframes animate-it { … }
.scroller {
scroll-timeline-name: --my-scroller;
scroll-timeline-axis: inline;
}
.scroller .subject {
animation: animate-it linear;
animation-timeline: --my-scroller;
}
Nếu muốn, bạn có thể kết hợp scroll-timeline-name và scroll-timeline-axis trong cú pháp rút gọn scroll-timeline. Ví dụ:
scroll-timeline: --my-scroller inline;
Bản minh hoạ: Chỉ báo bước băng chuyền ngang
Bản minh hoạ này có một chỉ báo bước xuất hiện phía trên mỗi băng chuyền hình ảnh. Khi một băng chuyền có 3 hình ảnh, thanh chỉ báo sẽ bắt đầu ở chiều rộng 33% để cho biết bạn hiện đang xem hình ảnh thứ nhất trong số 3 hình ảnh. Khi hình ảnh cuối cùng xuất hiện (xác định bằng cách cuộn đến cuối), chỉ báo sẽ chiếm toàn bộ chiều rộng của trình cuộn. Một Dòng thời gian tiến trình cuộn có tên được dùng để điều khiển ảnh động.
✨ Hãy tự mình dùng thử
Sau đây là mã đánh dấu cơ bản cho một thư viện:
<div class="gallery" style="--num-images: 2;">
<div class="gallery__scrollcontainer">
<div class="gallery__progress"></div>
<div class="gallery__entry">…</div>
<div class="gallery__entry">…</div>
</div>
</div>
Phần tử .gallery__progress được đặt ở vị trí tuyệt đối trong phần tử bao bọc .gallery. Kích thước ban đầu của thành phần này được xác định bằng thuộc tính tuỳ chỉnh --num-images.
.gallery {
position: relative;
}
.gallery__progress {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 1em;
transform: scaleX(calc(1 / var(--num-images)));
}
.gallery__scrollcontainer bố trí các phần tử .gallery__entry có trong đó theo chiều ngang và là phần tử cuộn. Bằng cách theo dõi vị trí cuộn, .gallery__progress sẽ được tạo hiệu ứng động. Bạn có thể thực hiện việc này bằng cách tham chiếu đến Scroll Progress Timeline (Dòng thời gian tiến trình cuộn) có tên là --gallery__scrollcontainer.
@keyframes grow-progress {
to { transform: scaleX(1); }
}
.gallery__scrollcontainer {
overflow-x: scroll;
scroll-timeline: --gallery__scrollcontainer inline;
}
.gallery__progress {
animation: auto grow-progress linear forwards;
animation-timeline: --gallery__scrollcontainer;
}
Tạo dòng thời gian tiến trình cuộn bằng JavaScript
Để tạo một Dòng thời gian cuộn trong JavaScript, hãy tạo một phiên bản mới của lớp ScrollTimeline. Truyền vào một nhóm thuộc tính có source và axis mà bạn muốn theo dõi.
source: Tham chiếu đến phần tử có trình cuộn mà bạn muốn theo dõi. Sử dụngdocument.documentElementđể nhắm đến trình cuộn gốc.axis: Xác định trục cần theo dõi. Tương tự như biến thể CSS, các giá trị được chấp nhận làblock,inline,xvày.
const tl = new ScrollTimeline({
source: document.documentElement,
});
Để đính kèm đối tượng này vào một Ảnh động trên web, hãy truyền đối tượng này vào dưới dạng thuộc tính timeline và bỏ qua mọi duration nếu có.
$el.animate({
opacity: [0, 1],
}, {
timeline: tl,
});
Bản minh hoạ: Chỉ báo tiến trình đọc (phiên bản mới)
Để tạo lại chỉ báo tiến trình đọc bằng JavaScript trong khi sử dụng cùng một mã đánh dấu, hãy dùng mã JavaScript sau:
const $progressbar = document.querySelector('#progress');
$progressbar.style.transformOrigin = '0% 50%';
$progressbar.animate(
{
transform: ['scaleX(0)', 'scaleX(1)'],
},
{
fill: 'forwards',
timeline: new ScrollTimeline({
source: document.documentElement,
}),
}
);
Kết quả trực quan trong phiên bản CSS là giống nhau: timeline được tạo sẽ theo dõi trình cuộn gốc và tăng tỷ lệ #progress trên trục x từ 0% lên 100% khi bạn cuộn trang.
✨ Hãy tự mình dùng thử
Thực hành với tính năng Xem tiến trình theo dòng thời gian
Tạo Dòng thời gian tiến trình xem ẩn danh trong CSS
Để tạo Dòng thời gian tiến trình của khung hiển thị, hãy dùng hàm view(). Các đối số được chấp nhận là <axis> và <view-timeline-inset>.
<axis>giống như trong Dòng thời gian tiến trình cuộn và xác định trục cần theo dõi. Giá trị mặc định làblock.- Với
<view-timeline-inset>, bạn có thể chỉ định một độ lệch (dương hoặc âm) để điều chỉnh ranh giới khi một phần tử được coi là có trong khung hiển thị hay không. Giá trị phải là tỷ lệ phần trăm hoặcauto, trong đóautolà giá trị mặc định.
Ví dụ: để liên kết một ảnh động với một phần tử giao nhau với trình cuộn của phần tử đó trên trục khối, hãy sử dụng view(block). Tương tự như scroll(), hãy đặt giá trị này làm giá trị cho thuộc tính animation-timeline và đừng quên đặt animation-duration thành auto.
Khi dùng mã sau, mọi img sẽ mờ dần khi vượt qua khung hiển thị trong lúc bạn di chuyển.
@keyframes reveal {
from { opacity: 0; }
to { opacity: 1; }
}
img {
animation: reveal linear;
animation-timeline: view();
}
Khoảng thời gian tạm ngưng: Xem các phạm vi trên Dòng thời gian
Theo mặc định, ảnh động được liên kết với Dòng thời gian của khung hiển thị sẽ gắn vào toàn bộ dải dòng thời gian. Thời gian này bắt đầu từ thời điểm đối tượng sắp vào scrollport và kết thúc khi đối tượng rời khỏi scrollport hoàn toàn.
Bạn cũng có thể liên kết chú thích này với một phần cụ thể của Dòng thời gian xem bằng cách chỉ định phạm vi mà chú thích sẽ gắn vào. Ví dụ: chỉ khi đối tượng đang vào vùng cuộn. Trong hình ảnh minh hoạ sau, tiến trình bắt đầu tăng từ 0% khi đối tượng đi vào vùng chứa có thể cuộn nhưng đã đạt đến 100% từ thời điểm đối tượng hoàn toàn giao nhau.
Sau đây là các phạm vi có thể có của View Timeline mà bạn có thể nhắm đến:
cover: Biểu thị toàn bộ phạm vi của dòng thời gian tiến trình xem.entry: Biểu thị phạm vi trong đó hộp chính đang chuyển sang phạm vi hiển thị tiến trình xem.exit: Biểu thị phạm vi trong đó hộp chính thoát khỏi phạm vi hiển thị tiến trình xem.entry-crossing: Biểu thị phạm vi mà hộp chính vượt qua cạnh đường viền cuối.exit-crossing: Biểu thị phạm vi mà hộp chính vượt qua cạnh đường viền bắt đầu.contain: Biểu thị phạm vi mà hộp chính được chứa hoàn toàn hoặc bao phủ hoàn toàn phạm vi hiển thị tiến trình xem trong cổng cuộn. Điều này phụ thuộc vào việc chủ thể cao hơn hay thấp hơn thanh cuộn.
Để xác định một phạm vi, bạn phải đặt range-start và range-end. Mỗi phần bao gồm range-name (xem danh sách ở trên) và range-offset để xác định vị trí trong range-name đó. Độ lệch phạm vi thường là một tỷ lệ phần trăm trong khoảng từ 0% đến 100% nhưng bạn cũng có thể chỉ định một độ dài cố định như 20em.
Ví dụ: nếu bạn muốn chạy một ảnh động từ thời điểm một đối tượng xuất hiện, hãy chọn entry 0% làm điểm bắt đầu của phạm vi. Để hoàn thành trước khi đối tượng nhập, hãy chọn entry 100% làm giá trị cho phạm vi kết thúc.
Trong CSS, bạn đặt thuộc tính này bằng cách sử dụng thuộc tính animation-range. Ví dụ:
animation-range: entry 0% entry 100%;
Trong JavaScript, hãy sử dụng các thuộc tính rangeStart và rangeEnd.
$el.animate(
keyframes,
{
timeline: tl,
rangeStart: 'entry 0%',
rangeEnd: 'entry 100%',
}
);
Hãy sử dụng công cụ được nhúng bên dưới để xem mỗi tên phạm vi đại diện cho điều gì và tỷ lệ phần trăm ảnh hưởng đến vị trí bắt đầu và kết thúc như thế nào. Hãy thử đặt range-start thành entry 0% và range-end thành cover 50%, sau đó kéo thanh cuộn để xem kết quả của ảnh động.
Xem bản ghi
Như bạn có thể nhận thấy khi dùng thử công cụ Phạm vi dòng thời gian của khung hiển thị này, một số phạm vi có thể được nhắm đến bằng 2 tổ hợp tên phạm vi + độ lệch phạm vi khác nhau. Ví dụ: entry 0%, entry-crossing 0% và cover 0% đều nhắm đến cùng một khu vực.
Khi range-start và range-end nhắm đến cùng một range-name và trải dài toàn bộ phạm vi (từ 0% đến 100%), bạn có thể rút ngắn giá trị thành tên phạm vi. Ví dụ: bạn có thể viết lại animation-range: entry 0% entry 100%; thành animation-range: entry ngắn hơn nhiều.
Bản minh hoạ: Lật hình ảnh
Bản minh hoạ này làm mờ hình ảnh khi chúng xuất hiện trong cổng cuộn. Việc này được thực hiện bằng cách sử dụng một Dòng thời gian xem ẩn danh. Phạm vi ảnh động đã được điều chỉnh để mỗi hình ảnh có độ mờ tối đa khi nằm ở giữa trình cuộn.
✨ Hãy tự mình dùng thử
Hiệu ứng mở rộng đạt được bằng cách sử dụng một đường dẫn cắt được tạo ảnh động. CSS được dùng cho hiệu ứng này là:
@keyframes reveal {
from { opacity: 0; clip-path: inset(0% 60% 0% 50%); }
to { opacity: 1; clip-path: inset(0% 0% 0% 0%); }
}
.revealing-image {
animation: auto linear reveal both;
animation-timeline: view();
animation-range: entry 25% cover 50%;
}
Tạo Dòng thời gian tiến trình xem có tên trong CSS
Tương tự như cách Dòng thời gian cuộn có các phiên bản được đặt tên, bạn cũng có thể tạo Dòng thời gian xem được đặt tên. Thay vì các thuộc tính scroll-timeline-*, bạn sử dụng các biến thể có tiền tố view-timeline-, cụ thể là view-timeline-name và view-timeline-axis.
Các giá trị cùng loại sẽ được áp dụng và các quy tắc tương tự để tra cứu dòng thời gian được đặt tên cũng sẽ được áp dụng.
Bản minh hoạ: Lật hình ảnh, phiên bản mới
Khi làm lại bản minh hoạ hiệu ứng lộ ảnh từ trước đó, mã đã sửa đổi sẽ có dạng như sau:
.revealing-image {
view-timeline-name: --revealing-image;
view-timeline-axis: block;
animation: auto linear reveal both;
animation-timeline: --revealing-image;
animation-range: entry 25% cover 50%;
}
Khi dùng view-timeline-name: revealing-image, phần tử sẽ được theo dõi trong trình cuộn gần nhất. Sau đó, giá trị này sẽ được dùng làm giá trị cho thuộc tính animation-timeline. Kết quả hiển thị hoàn toàn giống như trước.
✨ Hãy tự mình dùng thử
Tạo Dòng thời gian tiến trình xem bằng JavaScript
Để tạo Dòng thời gian hiển thị bằng JavaScript, hãy tạo một phiên bản mới của lớp ViewTimeline. Truyền vào một nhóm thuộc tính với subject mà bạn muốn theo dõi, axis và inset.
subject: Tham chiếu đến phần tử mà bạn muốn theo dõi trong trình cuộn riêng.axis: Trục cần theo dõi. Tương tự như biến thể CSS, các giá trị được chấp nhận làblock,inline,xvày.inset: Mức điều chỉnh phần lồng ghép (dương) hoặc phần lồng ghép bên ngoài (âm) của cổng cuộn khi xác định xem hộp có ở trong chế độ xem hay không.
const tl = new ViewTimeline({
subject: document.getElementById('subject'),
});
Để đính kèm đối tượng này vào một Ảnh động trên web, hãy truyền đối tượng này vào dưới dạng thuộc tính timeline và bỏ qua mọi duration nếu có. Bạn có thể truyền thông tin về phạm vi bằng cách sử dụng các thuộc tính rangeStart và rangeEnd.
$el.animate({
opacity: [0, 1],
}, {
timeline: tl,
rangeStart: 'entry 25%',
rangeEnd: 'cover 50%',
});
✨ Hãy tự mình dùng thử
Những điều khác bạn có thể thử
Đính kèm vào nhiều dải Dòng thời gian của khung hiển thị bằng một nhóm khung hình chính
Hãy xem bản minh hoạ danh sách liên hệ này, trong đó các mục trong danh sách được tạo hiệu ứng động. Khi một mục trong danh sách đi vào cổng cuộn từ dưới cùng, mục đó sẽ trượt và mờ dần; còn khi thoát khỏi cổng cuộn ở trên cùng, mục đó sẽ trượt và mờ dần.
✨ Hãy tự mình dùng thử
Trong bản minh hoạ này, mỗi phần tử được trang trí bằng một Dòng thời gian của khung hiển thị theo dõi phần tử khi phần tử đó đi qua cổng cuộn, nhưng có 2 ảnh động dựa trên thao tác cuộn được đính kèm vào phần tử đó. Ảnh động animate-in được đính kèm vào dải entry của dòng thời gian và ảnh động animate-out được đính kèm vào dải exit của dòng thời gian.
@keyframes animate-in {
0% { opacity: 0; transform: translateY(100%); }
100% { opacity: 1; transform: translateY(0); }
}
@keyframes animate-out {
0% { opacity: 1; transform: translateY(0); }
100% { opacity: 0; transform: translateY(-100%); }
}
#list-view li {
animation: animate-in linear forwards,
animate-out linear forwards;
animation-timeline: view();
animation-range: entry, exit;
}
Thay vì chạy hai ảnh động riêng biệt được đính kèm vào hai dải ô riêng biệt, bạn cũng có thể tạo một bộ khoá khung hình đã chứa thông tin về dải ô.
@keyframes animate-in-and-out {
entry 0% {
opacity: 0; transform: translateY(100%);
}
entry 100% {
opacity: 1; transform: translateY(0);
}
exit 0% {
opacity: 1; transform: translateY(0);
}
exit 100% {
opacity: 0; transform: translateY(-100%);
}
}
#list-view li {
animation: linear animate-in-and-out;
animation-timeline: view();
}
Vì khung hình chính chứa thông tin về phạm vi, nên bạn không cần chỉ định animation-range. Kết quả hoàn toàn giống như trước.
✨ Hãy tự mình dùng thử
Đính kèm vào Dòng thời gian cuộn không phải là dòng thời gian gốc
Cơ chế tra cứu cho Dòng thời gian cuộn được đặt tên và Dòng thời gian xem được đặt tên chỉ giới hạn ở các thành phần cuộn cấp trên. Tuy nhiên, rất thường xuyên, phần tử cần được tạo hiệu ứng không phải là phần tử con của trình cuộn cần được theo dõi.
Để làm được việc này, bạn cần sử dụng thuộc tính timeline-scope. Bạn dùng thuộc tính này để khai báo một dòng thời gian có tên đó mà không cần thực sự tạo dòng thời gian. Điều này giúp dòng thời gian có tên đó có phạm vi rộng hơn. Trên thực tế, bạn dùng thuộc tính timeline-scope trên một phần tử mẹ dùng chung để dòng thời gian của trình cuộn con có thể đính kèm vào phần tử đó.
Ví dụ:
.parent {
timeline-scope: --tl;
}
.parent .scroller {
scroll-timeline: --tl;
}
.parent .scroller ~ .subject {
animation: animate linear;
animation-timeline: --tl;
}
Trong đoạn mã này:
- Phần tử
.parentkhai báo một dòng thời gian có tên là--tl. Mọi thành phần con của thành phần này đều có thể tìm và sử dụng thành phần này làm giá trị cho thuộc tínhanimation-timeline. - Phần tử
.scrollerthực sự xác định một Dòng thời gian cuộn có tên là--tl. Theo mặc định, thành phần này sẽ chỉ hiển thị cho các thành phần con, nhưng vì.parentđã đặt thànhscroll-timeline-root, nên thành phần này sẽ được đính kèm vào.parent. - Phần tử
.subjectsử dụng dòng thời gian--tl. Nó sẽ đi lên cây tổ tiên và tìm--tltrên.parent. Với--tltrên.parenttrỏ đến--tlcủa.scroller,.subjectvề cơ bản sẽ theo dõi Dòng thời gian tiến trình cuộn của.scroller.
Nói cách khác, bạn có thể dùng timeline-root để di chuyển một dòng thời gian lên một thành phần cấp trên (còn gọi là hoisting), nhờ đó tất cả các thành phần con của thành phần cấp trên đều có thể truy cập vào dòng thời gian đó.
Bạn có thể dùng thuộc tính timeline-scope với cả Dòng thời gian cuộn và Dòng thời gian hiển thị.
Các bản minh hoạ và tài nguyên khác
Tất cả các bản minh hoạ được đề cập trong bài viết này trên trang web thu nhỏ scroll-driven-animations.style. Trang web này có nhiều bản minh hoạ khác để làm nổi bật những tính năng có thể thực hiện được bằng ảnh động dựa trên thao tác cuộn.
Một trong những bản minh hoạ bổ sung là danh sách bìa đĩa này. Mỗi bìa sẽ xoay theo không gian 3D khi được chiếu sáng ở trung tâm.
✨ Hãy tự mình dùng thử
Hoặc bản minh hoạ thẻ xếp chồng này tận dụng position: sticky. Khi các thẻ xếp chồng lên nhau, các thẻ đã bị kẹt sẽ thu nhỏ lại, tạo ra hiệu ứng chiều sâu đẹp mắt. Cuối cùng, toàn bộ ngăn xếp sẽ trượt ra khỏi chế độ xem dưới dạng một nhóm.
✨ Hãy tự mình dùng thử
Ngoài ra, scroll-driven-animations.style còn có một bộ sưu tập các công cụ như hình ảnh trực quan về Tiến trình phạm vi dòng thời gian của khung hiển thị mà chúng ta đã đề cập trước đó trong bài đăng này.
Ảnh động dựa trên thao tác cuộn cũng được đề cập trong phần Có gì mới trong Web Animations tại Google I/O 2023.