Hoạt hình rất quan trọng cho trải nghiệm người dùng thú vị trên nhiều ứng dụng. Có nhiều cách để thực hiện các hình ảnh động web, chẳng hạn như CSS ________ 3/________ 4 hoặc hoạt hình dựa trên JavaScript (sử dụng requestAnimationFrame()). Trong bài viết này, chúng tôi phân tích sự khác biệt về hiệu suất giữa hoạt hình dựa trên CSS và dựa trên JavaScript. Cả hai chuyển tiếp CSS và hình ảnh động có thể được sử dụng để viết hoạt hình. Họ mỗi người có kịch bản người dùng riêng: Về hiệu suất, không có sự khác biệt giữa việc thực hiện một hình ảnh động với các chuyển tiếp CSS hoặc hoạt hình. Cả hai đều được phân loại theo cùng một chiếc ô dựa trên CSS trong bài viết này. API requestAnimationFrame() cung cấp một cách hiệu quả để tạo hình ảnh động trong JavaScript. Hàm gọi lại của phương thức được trình duyệt gọi trước lần lặp tiếp theo trên mỗi khung hình. So với ________ 9/________ 10, cần một tham số độ trễ cụ thể, requestAnimationFrame() hiệu quả hơn nhiều. Các nhà phát triển có thể tạo một hình ảnh động bằng cách thay đổi kiểu của một phần tử mỗi khi vòng lặp được gọi (hoặc cập nhật bản vẽ Canvas hoặc bất cứ điều gì.) Lưu ý: Giống như chuyển đổi CSS và hình ảnh động, requestAnimationFrame() tạm dừng khi tab hiện tại được đẩy vào nền. Like CSS
transitions and animations, requestAnimationFrame() pauses when the current tab is pushed into the background. Để biết thêm chi tiết, hãy đọc hoạt hình với JavaScript từ SetInterVal đến RequestAnimationFrame. Thực tế là, trong hầu hết các trường hợp, hiệu suất của các hình ảnh động dựa trên CSS gần giống như hình ảnh động của Javascrip-ít nhất là trong Firefox. Một số thư viện hoạt hình dựa trên JavaScript, như GSAP và Velocity.js, thậm chí tuyên bố rằng họ có thể đạt được hiệu suất tốt hơn so với chuyển đổi/hoạt hình CSS gốc. Điều này có thể xảy ra do các chuyển đổi/hình ảnh động CSS là các kiểu phần tử được lấy mẫu lại trong luồng giao diện người dùng chính trước khi mỗi sự kiện lặp lại xảy ra, gần giống như các kiểu phần tử lấy mẫu lại thông qua cuộc gọi lại requestAnimationFrame(), cũng được kích hoạt trước lần lặp tiếp theo. Nếu cả hai hình ảnh động được thực hiện trong chuỗi UI chính, không có hiệu suất khác biệt. Trong phần này, chúng tôi sẽ hướng dẫn bạn qua một bài kiểm tra hiệu suất, sử dụng Firefox, để xem phương pháp hoạt hình nào có vẻ tốt hơn tổng thể. Trước khi đi qua ví dụ, vui lòng bật các công cụ FPS trước để xem tốc độ khung hình hiện tại:Chuyển tiếp CSS và hình ảnh động
requestAnimationFrame
So sánh hiệu suất: Chuyển tiếp so với RequestAnimationFrame
transitions vs. requestAnimationFrameCho phép các công cụ FPS
Chạy kiểm tra hiệu suất
Ban đầu trong thử nghiệm được thấy dưới đây, tổng cộng 1000 phần tử <div id="header"> <button id="toggle-button">Toggle</button> <span id="type">CSS Animation</span> </div> <div id="box-container"></div> 7 được chuyển đổi bởi hoạt hình CSS.
const boxes = []; const button = document.getElementById("toggle-button"); const boxContainer = document.getElementById("box-container"); const animationType = document.getElementById("type"); // create boxes for (let i = 0; i < 1000; i++) { const div = document.createElement("div"); div.classList.add("css-animation"); div.classList.add("box"); boxContainer.appendChild(div); boxes.push(div.style); } let toggleStatus = true; let rafId; button.addEventListener("click", () => { if (toggleStatus) { animationType.textContent = " requestAnimationFrame"; for (const child of boxContainer.children) { child.classList.remove("css-animation"); } rafId = window.requestAnimationFrame(animate); } else { window.cancelAnimationFrame(rafId); animationType.textContent = " CSS animation"; for (const child of boxContainer.children) { child.classList.add("css-animation"); } } toggleStatus = !toggleStatus; }); const duration = 6000; const translateX = 500; const rotate = 360; const scale = 1.4 - 0.6; let start; function animate(time) { if (!start) { start = time; rafId = window.requestAnimationFrame(animate); return; } const progress = (time - start) / duration; if (progress < 2) { let x = progress * translateX; let transform; if (progress >= 1) { x = (2 - progress) * translateX; transform = `translateX(${x}px) rotate(${ (2 - progress) * rotate }deg) scale(${0.6 + (2 - progress) * scale})`; } else { transform = `translateX(${x}px) rotate(${progress * rotate}deg) scale(${ 0.6 + progress * scale })`; } for (const box of boxes) { box.transform = transform; } } else { start = null; } rafId = window.requestAnimationFrame(animate); }
<div id="header"> <button id="toggle-button">Toggle</button> <span id="type">CSS Animation</span> </div> <div id="box-container"></div>
#header { position: sticky; top: 0.5rem; margin: 0 0.5rem; z-index: 100; background-color: lightgreen; } #box-container { margin-top: 1.5rem; display: grid; grid-template-columns: repeat(40, 1fr); gap: 15px; } .box { width: 30px; height: 30px; background-color: red; } .css-animation { animation: animate 6s linear 0s infinite alternate; } @keyframes animate { 0% { transform: translateX(0) rotate(0deg) scale(0.6); } 100% { transform: translateX(500px) rotate(360deg) scale(1.4); } }
Hoạt hình có thể được chuyển sang requestAnimationFrame() bằng cách nhấp vào nút chuyển đổi.
Hãy thử chạy cả hai ngay bây giờ, so sánh FPS cho mỗi (hộp màu tím đầu tiên.) Bạn sẽ thấy rằng hiệu suất của hình ảnh động CSS và requestAnimationFrame() rất gần.
Tắt hoạt hình chủ đề chính
Ngay cả khi đưa ra kết quả kiểm tra ở trên, chúng tôi sẽ lập luận rằng hoạt hình CSS là lựa chọn tốt hơn. Nhưng bằng cách nào? Điều quan trọng là miễn là các thuộc tính mà chúng tôi muốn làm động không kích hoạt Refle/REPAINT (đọc các kích hoạt CSS để biết thêm thông tin), chúng tôi có thể chuyển các hoạt động lấy mẫu đó ra khỏi luồng chính. Thuộc tính phổ biến nhất là biến đổi CSS. Nếu một phần tử được quảng bá như một lớp, các thuộc tính biến đổi hoạt hình có thể được thực hiện trong GPU, có nghĩa là hiệu suất/hiệu quả tốt hơn, đặc biệt là trên thiết bị di động. Tìm hiểu thêm chi tiết trong OffMainThreadCompositing.
Để kích hoạt OMTA (tắt hoạt hình chủ đề chính) trong Firefox, bạn có thể truy cập về: Cấu hình và tìm kiếm #header { position: sticky; top: 0.5rem; margin: 0 0.5rem; z-index: 100; background-color: lightgreen; } #box-container { margin-top: 1.5rem; display: grid; grid-template-columns: repeat(40, 1fr); gap: 15px; } .box { width: 30px; height: 30px; background-color: red; } .css-animation { animation: animate 6s linear 0s infinite alternate; } @keyframes animate { 0% { transform: translateX(0) rotate(0deg) scale(0.6); } 100% { transform: translateX(500px) rotate(360deg) scale(1.4); } } 0. Chuyển giá trị của nó thành <div id="header"> <button id="toggle-button">Toggle</button> <span id="type">CSS Animation</span> </div> <div id="box-container"></div> 6.
Sau khi bật OMTA, hãy thử chạy lại bài kiểm tra trên. Bạn sẽ thấy rằng FPS của hình ảnh động CSS bây giờ sẽ cao hơn đáng kể.
Lưu ý: Trong phiên bản hàng đêm/nhà phát triển, bạn sẽ thấy OMTA được bật theo mặc định, vì vậy bạn có thể phải thực hiện các bài kiểm tra theo cách khác (kiểm tra với nó được bật trước, sau đó vô hiệu hóa để kiểm tra mà không cần OMTA.) In Nightly/Developer Edition, you should see that OMTA is enabled by default, so you might have to do the tests the other way around (test with it enabled first, then disable to test without OMTA.)
Bản tóm tắt
Trình duyệt có thể tối ưu hóa các luồng kết xuất. Tóm lại, chúng ta nên luôn luôn cố gắng tạo hình ảnh động của mình bằng cách sử dụng chuyển đổi/hình ảnh động CSS nếu có thể. Nếu hình ảnh động của bạn thực sự phức tạp, bạn có thể phải dựa vào hình ảnh động dựa trên JavaScript.