1. Trước khi bắt đầu
Hiệu ứng chuyển động theo thao tác cuộn cho phép bạn kiểm soát việc phát ảnh động dựa trên vị trí cuộn của vùng chứa cuộn. Điều này có nghĩa là khi bạn cuộn lên hoặc xuống, ảnh động sẽ tua đi hoặc tua lại. Ngoài ra, với hiệu ứng chuyển động theo thao tác cuộn, bạn cũng có thể kiểm soát ảnh động dựa trên vị trí của một phần tử trong vùng chứa cuộn. Điều này cho phép bạn tạo các hiệu ứng thú vị như hình nền thị sai, thanh tiến trình cuộn và hình ảnh tự hiển thị khi xuất hiện trong khung hiển thị.
Chrome 115 mới hỗ trợ một tập hợp các lớp JavaScript và thuộc tính CSS cho phép bạn dễ dàng tạo hiệu ứng chuyển động theo thao tác cuộn mang tính khai báo. Các API mới này hoạt động cùng với các API Ảnh động trên web và Ảnh động CSS hiện có.
Lớp học lập trình này sẽ hướng dẫn bạn cách tạo hiệu ứng chuyển động theo thao tác cuộn bằng CSS. Khi hoàn thành lớp học lập trình này, bạn sẽ làm quen với nhiều thuộc tính CSS mới do tính năng thú vị này giới thiệu, chẳng hạn như scroll-timeline, view-timeline, animation-timeline và animation-range.
Kiến thức bạn sẽ học được
- Cách tạo hiệu ứng nền thị sai bằng Dòng thời gian cuộn trong CSS.
- Cách tạo thanh tiến trình bằng Dòng thời gian cuộn trong CSS.
- Cách tạo hiệu ứng hiển thị hình ảnh bằng Dòng thời gian khung hiển thị trong CSS.
- Cách nhắm mục tiêu đến nhiều loại phạm vi của Dòng thời gian khung hiển thị trong CSS.
Bạn cần có
Một trong những tổ hợp thiết bị sau:
- Phiên bản Chrome gần đây (115 trở lên) trên ChromeOS, macOS hoặc Windows có cờ "Experimental Web Platform Features" (Tính năng nền tảng web thử nghiệm) được đặt thành bật.
- Hiểu biết cơ bản về HTML
- Hiểu biết cơ bản về CSS, đặc biệt là ảnh động trong CSS
2. Bắt đầu thiết lập
Mọi thứ bạn cần cho dự án này đều có trong kho lưu trữ GitHub. Để bắt đầu, hãy sao chép mã và mở mã đó trong môi trường phát triển mà bạn yêu thích.
- Mở một thẻ trình duyệt mới rồi chuyển đến https://github.com/googlechromelabs/io23-scroll-driven-animations-codelab.
- Nhân bản kho lưu trữ.
- Mở mã trong IDE mà bạn muốn.
- Chạy
npm installđể cài đặt các phần phụ thuộc. - Chạy
npm startvà truy cập vào http://localhost:3000/. - Ngoài ra, nếu bạn chưa cài đặt npm, hãy mở tệp
src/index.htmltrong Chrome.
3. Tìm hiểu về dòng thời gian ả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 tài liệu. Điều đó có nghĩa là khi trang tải, ảnh động sẽ tiến lên khi thời gian trôi qua. Đây là dòng thời gian ảnh động mặc định và cho đến nay, đây là dòng thời gian ảnh động duy nhất mà bạn có quyền truy cập.
Với hiệu ứng chuyển động theo thao tác cuộn, bạn có quyền truy cập vào 2 loại dòng thời gian mới:
- Dòng thời gian tiến trình cuộn
- Dòng thời gian tiến trình khung hiển thị
Trong CSS, bạn có thể đính kèm các dòng thời gian này vào ảnh động bằng thuộc tính animation-timeline. Hãy xem ý nghĩa của các dòng thời gian mới này và cách chúng khác nhau.
Dòng thời gian tiến trình cuộn
Dòng thời gian tiến trình cuộn là dòng thời gian ảnh động được liên kết với tiến trình ở vị trí cuộn của vùng chứa cuộn (còn gọi là khung hiển thị cuộn hoặc trình cuộn) dọc theo một trục cụ thể. Dòng thời gian 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 dọc theo dòng thời gian.
Vị trí cuộn bắt đầu biểu thị tiến trình 0% và vị trí cuộn kết thúc biểu thị tiến trình 100%. Trong hình ảnh trực quan sau đây, hãy lưu ý rằng tiến trình sẽ tăng từ 0% lên 100% khi bạn cuộn xuống thanh cuộn.
Dòng thời gian tiến trình khung hiển thị
Loại dòng thời gian 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 cuộn. Giống như Dòng thời gian tiến trình cuộn, độ lệch cuộn của thanh cuộn sẽ đượ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 trình cuộn đó sẽ xác định tiến trình. Điều này có thể so sánh với IntersectionObserver, 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 hiển thị trong trình cuộn, thì phần tử đó sẽ không giao nhau. Nếu phần tử hiển thị bên trong trình cuộn (ngay cả đối với phần nhỏ nhất), thì phần tử đó sẽ giao nhau.
Dòng thời gian tiến trình khung hiển thị bắt đầu từ thời điểm một đối tượng bắt đầu giao nhau với trình cuộn và kết thúc khi đối tượng ngừng giao nhau với trình cuộn. Trong hình ảnh trực quan sau đây, hãy lưu ý rằng tiến trình bắt đầu tăng từ 0% khi đối tượng nhập vùng chứa cuộn và đạt đến 100% vào thời điểm đối tượng rời khỏi vùng chứa cuộn.
Theo mặc định, ảnh động được liên kết với Dòng thời gian tiến trình khung hiển thị sẽ đính kèm vào toàn bộ phạm vi của dòng thời gian đó. Ảnh động này bắt đầu từ thời điểm đối tượng nhập khung hiển thị cuộn và kết thúc khi đối tượng rời khỏi khung hiển thị cuộn.
Bạn cũng có thể liên kết ảnh động với một phần cụ thể của Dòng thời gian tiến trình khung hiển thị bằng cách chỉ định phạm vi mà ảnh động đó sẽ đính kèm. Ví dụ: chỉ khi đối tượng đang nhập trình cuộn. Trong hình ảnh trực quan sau đây, tiến trình bắt đầu tăng từ 0% khi đối tượng nhập vùng chứa cuộn nhưng đã đạt đến 100% kể từ thời điểm đối tượng giao nhau hoàn toàn.
Các phạm vi Dòng thời gian khung hiển thị mà bạn có thể nhắm mục tiêu là cover, contain, entry, exit, entry-crossing, và exit-crossing. Các phạm vi này sẽ được giải thích sau trong lớp học lập trình này. Tuy nhiên, nếu bạn không thể chờ đợi để biết, hãy sử dụng công cụ tại https://goo.gle/view-timeline-range-tool để xem mỗi phạm vi đại diện cho điều gì.
4. Tạo hiệu ứng nền thị sai
Hiệu ứng đầu tiên cần thêm vào trang là hiệu ứng nền thị sai trên hình nền chính. Khi bạn cuộn xuống trang, hình nền sẽ di chuyển, mặc dù với tốc độ khác nhau. Để thực hiện việc này, bạn dựa vào Dòng thời gian tiến trình cuộn.
Để triển khai hiệu ứng này, bạn cần thực hiện 2 bước:
- Tạo ảnh động di chuyển vị trí của hình nền.
- Liên kết ảnh động với tiến trình cuộn của tài liệu.
Tạo ảnh động
- Để tạo ảnh động, hãy sử dụng một tập hợp khung hình chính thông thường. Trong đó, hãy di chuyển vị trí nền từ 0% theo chiều dọc đến 100%:
src/styles.css
@keyframes move-background {
from {
background-position: 50% 0%;
}
to {
background-position: 50% 100%;
}
}
- Bây giờ, hãy đính kèm các khung hình chính này vào phần tử body:
src/styles.css
body {
animation: 1s linear move-background;
}
Với đoạn mã này, ảnh động move-background sẽ được thêm vào phần tử body. Thuộc tính animation-duration của ảnh động này được đặt thành 1 giây và sử dụng hiệu ứng chuyển động linear.
Liên kết ảnh động với tiến trình cuộn của gốc bằng Dòng thời gian tiến trình cuộn ẩn danh
Cách dễ nhất để tạo dòng thời gian tiến trình cuộn là sử dụng hàm scroll(). Hàm này tạo Dòng thời gian tiến trình cuộn ẩn danh mà bạn có thể đặt làm giá trị cho thuộc tính animation-timeline.
Hàm scroll() chấp nhận một đối số <scroller> và <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 của tổ tiên gần nhất (mặc định).root. Sử dụng khung nhìn tài liệu làm vùng chứa cuộn.self. Sử dụng chính phần tử làm vùng chứa cuộn.
Các giá trị được chấp nhận cho đối số <axis> là:
block. Sử dụng số đo tiến trình dọc theo trục khối của vùng chứa cuộn (mặc định).inline. Sử dụng số đo tiến trình dọc theo trục nội tuyến của vùng chứa cuộn.y. Sử dụng số đo tiến trình dọc theo trục y của vùng chứa cuộn.x. Sử dụng số đo tiến trình dọc theo trục x của vùng chứa cuộn.
Để liên kế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. Khi kết hợp, giá trị sẽ là scroll(root block).
- Đặt
scroll(root block)làm giá trị cho thuộc tínhanimation-timelinetrên body. - Hơn nữa, vì
animation-durationđược biểu thị bằng giây không có ý nghĩa, hãy đặt thời lượng thànhauto. Nếu bạn không chỉ địnhanimation-duration, giá trị này sẽ mặc định làauto.
src/styles.css
body {
animation: linear move-background;
animation-duration: auto;
animation-timeline: scroll(root block);
}
Vì trình cuộn gốc cũng là trình cuộn mẹ gần nhất cho phần tử body, nên bạn cũng có thể sử dụng giá trị nearest:
src/styles.css
body {
animation: linear move-background;
animation-duration: auto;
animation-timeline: scroll(nearest block);
}
Vì nearest và block là các giá trị mặc định, nên bạn thậm chí có thể chọn bỏ qua các giá trị này. Trong trường hợp đó, mã có thể được đơn giản hoá thành như sau:
src/styles.css
body {
animation: linear move-background;
animation-duration: auto;
animation-timeline: scroll();
}
Xác minh các thay đổi
Nếu mọi thứ diễn ra suôn sẻ, thì bây giờ bạn sẽ có như sau:
Nếu không, hãy xem nhánh solution-step-1 của mã.
5. Tạo thanh tiến trình cho thư viện hình ảnh
Trên trang có một băng chuyền ngang cần có thanh tiến trình để cho biết ảnh mà bạn hiện đang xem.
Đánh dấu cho băng chuyền có dạng như sau:
src/index.html
<div class="gallery">
<div class="gallery__scrollcontainer" style="--num-images: 3;">
<div class="gallery__progress"></div>
<div class="gallery__entry">
...
</div>
<div class="gallery__entry">
...
</div>
<div class="gallery__entry">
...
</div>
</div>
</div>
Các khung hình chính cho thanh tiến trình đã được đặt và có dạng như sau:
src/styles.css
@keyframes adjust-progress {
from {
transform: scaleX(calc(1 / var(--num-images)));
}
to {
transform: scaleX(1);
}
}
Ảnh động này cần được đính kèm vào phần tử .gallery__progress phần tử bằng Dòng thời gian tiến trình cuộn. Như minh hoạ trong bước trước, bạn có thể thực hiện việc này bằng cách tạo Dòng thời gian tiến trình cuộn ẩn danh bằng hàm scroll():
src/styles.css
.gallery__progress {
animation: linear adjust-progress;
animation-duration: auto;
animation-timeline: scroll(nearest inline);
}
Mặc dù đoạn mã này có vẻ như sẽ hoạt động, nhưng đoạn mã này không hoạt động do cách hoạt động của tính năng tra cứu vùng chứa cuộn tự động bằng nearest. Khi tra cứu trình cuộn gần nhất, phần tử sẽ chỉ xem xét các phần tử có thể ảnh hưởng đến vị trí của phần tử đó. Vì .gallery__progress được định vị tuyệt đối, nên phần tử mẹ đầu tiên sẽ xác định vị trí của phần tử đó là phần tử .gallery vì phần tử này đã áp dụng position: relative. Điều này có nghĩa là phần tử .gallery__scrollcontainer (là trình cuộn cần nhắm mục tiêu) hoàn toàn không được xem xét trong quá trình tra cứu tự động này.
Để giải quyết vấn đề này, hãy tạo Dòng thời gian tiến trình cuộn có tên trên phần tử .gallery__scrollcontainer và liên kết .gallery__progress với dòng thời gian đó bằng tên đó.
Tạo và liên kết Dòng thời gian tiến trình cuộn có tên
Để tạo 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 CSS scroll-timeline-name trên vùng chứa cuộn thành một giá trị mà bạn thích. Giá trị phải bắt đầu bằng --.
Vì thư viện cuộn theo chiều ngang, nên bạn cũng cần đặt thuộc tính scroll-timeline-axis. Các giá trị được phép giống như đố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 một giá trị với mã nhận dạng được dùng cho scroll-timeline-name.
- Thay đổi tệp
styles.cssđể bao gồm như sau:
src/styles.css
.gallery__scrollcontainer {
/* Create the gallery-is-scrolling timeline */
scroll-timeline-name: --gallery-is-scrolling;
scroll-timeline-axis: inline;
}
.gallery__progress {
animation: linear adjust-progress;
animation-duration: auto;
/* Set gallery-is-scrolling as the timeline */
animation-timeline: --gallery-is-scrolling;
}
Xác minh các thay đổi
Nếu mọi thứ diễn ra suôn sẻ, thì bây giờ bạn sẽ có như sau:
Nếu không, hãy xem nhánh solution-step-2 của mã.
6. Tạo ảnh động cho hình ảnh trong thư viện khi hình ảnh đó nhập và thoát khỏi khung hiển thị cuộn
Làm mờ dần hình ảnh trong thư viện
Thiết lập Dòng thời gian tiến trình khung hiển thị ẩn danh
Một hiệu ứng đẹp mắt cần thêm là làm mờ dần hình ảnh trong thư viện khi hình ảnh đó xuất hiện trong khung hiển thị. Để thực hiện việc này, bạn có thể sử dụng Dòng thời gian tiến trình khung hiển thị.
Để tạo Dòng thời gian tiến trình khung hiển thị, bạn có thể sử dụng hàm view(). Các đối số được chấp nhận là <axis> và <view-timeline-inset>.
<axis>giống như từ Dòng thời gian tiến trình cuộn và xác định trục cần theo dõi.- Với
<view-timeline-inset>, bạn có thể chỉ định độ lệch (dương hoặc âm) để điều chỉnh ranh giới khi một phần tử được coi là đang trong khung hiển thị hay không.
- Các khung hình chính đã được đặt, vì vậy, bạn chỉ cần đính kèm các khung hình chính đó. Để thực hiện việc này, hãy tạo Dòng thời gian tiến trình khung hiển thị trên mỗi phần tử
.gallery__entry.
src/styles.css
@keyframes animate-in {
from {
opacity: 0;
clip-path: inset(50% 0% 50% 0%);
}
to {
opacity: 1;
clip-path: inset(0% 0% 0% 0%);
}
}
.gallery__entry {
animation: linear animate-in;
animation-duration: auto;
animation-timeline: view(inline);
}
Giới hạn phạm vi của Dòng thời gian tiến trình khung hiển thị
Nếu bạn lưu CSS và tải trang, bạn sẽ thấy các phần tử mờ dần, nhưng có vẻ như có điều gì đó không ổn. Các phần tử này bắt đầu ở độ mờ 0 khi hoàn toàn nằm ngoài khung hiển thị và chỉ kết thúc ở độ mờ 1 khi đã thoát hoàn toàn.
Đó là vì phạm vi mặc định cho Dòng thời gian tiến trình khung hiển thị là phạm vi đầy đủ. Đây được gọi là phạm vi cover.
- Để chỉ nhắm mục tiêu đến phạm vi
entrycủa đối tượng, hãy sử dụng thuộc tính CSSanimation-rangeđể giới hạn thời điểm ảnh động sẽ chạy.
src/styles.css
.gallery__entry {
animation: linear fade-in;
animation-duration: auto;
animation-timeline: view(inline);
animation-range: entry 0% entry 100%;
}
Ảnh động hiện chạy từ entry 0% (đối tượng sắp nhập trình cuộn) đến entry 100% (đối tượng đã nhập hoàn toàn trình cuộn).
Các phạm vi Dòng thời gian khung hiển thị có thể có là:
cover. Biểu thị toàn bộ phạm vi của dòng thời gian tiến trình khung hiển thị.entry. Biểu thị phạm vi trong đó hộp chính đang nhập phạm vi hiển thị tiến trình khung hiển thị.exit. Biểu thị phạm vi trong đó hộp chính đang thoát khỏi phạm vi hiển thị tiến trình khung hiển thị.entry-crossing. Biểu thị phạm vi trong đó hộp chính vượt qua cạnh viền cuối.exit-crossing. Biểu thị phạm vi trong đó hộp chính vượt qua cạnh viền bắt đầu.contain. Biểu thị phạm vi trong đó 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 khung hiển thị trong khung hiển thị cuộn. Điều này phụ thuộc vào việc đối tượng cao hơn hay thấp hơn trình cuộn.
Sử dụng công cụ tại https://goo.gle/view-timeline-range-tool để xem mỗi 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.
- Vì phạm vi bắt đầu và kết thúc giống nhau ở đây và độ lệch mặc định được sử dụng, hãy đơn giản hoá
animation-rangethành một tên phạm vi ảnh động duy nhất:
src/styles.css
.gallery__entry {
animation: linear animate-in;
animation-duration: auto;
animation-timeline: view(inline);
animation-range: entry;
}
Làm mờ dần hình ảnh trong thư viện
- Để làm mờ dần hình ảnh khi hình ảnh đó thoát khỏi trình cuộn, bạn có thể thực hiện tương tự như ảnh động animate-in nhưng nhắm mục tiêu đến một phạm vi khác.
src/styles.css
@keyframes animate-out {
from {
opacity: 1;
clip-path: inset(0% 0% 0% 0%);
}
to {
opacity: 0;
clip-path: inset(50% 0% 50% 0%);
}
}
.gallery__entry {
animation: linear animate-in, linear animate-out;
animation-duration: auto;
animation-timeline: view(inline);
animation-range: entry, exit;
}
Các khung hình chính animate-in sẽ được áp dụng cho phạm vi entry và các khung hình chính animate-out cho phạm vi exit.
Xác minh các thay đổi
Nếu mọi thứ diễn ra suôn sẻ, thì bây giờ bạn sẽ có như sau:
Nếu không, hãy xem nhánh solution-step-3 của mã.
7. Tạo ảnh động cho hình ảnh trong thư viện khi hình ảnh đó nhập và thoát khỏi khung hiển thị cuộn, sử dụng một tập hợp khung hình chính
Trường hợp cho một tập hợp khung hình chính
Thay vì đính kèm 2 ảnh động vào các phạm vi khác nhau, bạn có thể tạo một tập hợp khung hình chính đã chứa thông tin phạm vi.
Hình dạng của các khung hình chính có dạng như sau:
@keyframes keyframes-name {
range-name range-offset {
...
}
range-name range-offset {
...
}
}
- Kết hợp các khung hình chính làm mờ dần và làm mờ dần như sau:
src/styles.css
@keyframes animate-in-and-out {
entry 0% {
opacity: 0;
clip-path: inset(50% 0% 50% 0%);
}
entry 90% {
opacity: 1;
clip-path: inset(0% 0% 0% 0%);
}
exit 10% {
opacity: 1;
clip-path: inset(0% 0% 0% 0%);
}
exit 100% {
opacity: 0;
clip-path: inset(50% 0% 50% 0%);
}
}
- Khi thông tin phạm vi có trong các khung hình chính, bạn không cần chỉ định
animation-rangeriêng nữa. Đính kèm các khung hình chính làm thuộc tínhanimation.
src/styles.css
.gallery__entry {
animation: linear animate-in-and-out both;
animation-duration: auto;
animation-timeline: view(inline);
}
Xác minh các thay đổi
Nếu mọi thứ diễn ra suôn sẻ, thì bạn sẽ có kết quả tương tự như ở bước trước. Nếu không, hãy xem nhánh solution-step-4 của mã.
8. Xin chúc mừng!
Bạn đã hoàn thành lớp học lập trình này và giờ đây đã biết cách tạo Dòng thời gian tiến trình cuộn và Dòng thời gian tiến trình khung hiển thị trong CSS!
Tìm hiểu thêm
Tài nguyên: