Ảnh động trên web từng là đặc quyền của JavaScript, nhưng khi thế giới chuyển sang thiết bị di động, ảnh động đã chuyển sang CSS để sử dụng cú pháp khai báo và các tính năng tối ưu hoá mà trình duyệt có thể thực hiện. Với mục tiêu luôn là 60 khung hình/giây trên thiết bị di động, bạn không nên vượt quá những gì trình duyệt biết cách hiển thị một cách hiệu quả.
Ngày càng có nhiều công cụ xuất hiện để giúp ảnh động do JavaScript điều khiển hoạt động hiệu quả hơn, nhưng mục tiêu chính là hợp nhất ảnh động khai báo và mệnh lệnh , trong đó quyết định về cách viết ảnh động dựa trên mã rõ ràng nhất, chứ không phải những gì có thể thực hiện được ở một dạng và không thể thực hiện được ở dạng khác.
Ảnh động trên web sẽ đáp ứng yêu cầu đó và phần đầu tiên của tính năng này đã ra mắt trong Chrome 36 dưới dạng element.animate()
. Hàm mới này cho phép bạn tạo ảnh động hoàn toàn bằng JavaScript và chạy ảnh động đó hiệu quả như mọi Ảnh động hoặc Hiệu ứng chuyển đổi CSS (thực tế, kể từ Chrome 34, công cụ Ảnh động trên web chính xác là công cụ điều khiển tất cả các phương thức này).
Cú pháp này rất đơn giản và bạn sẽ thấy quen thuộc với các phần của cú pháp này nếu từng viết hiệu ứng Chuyển đổi hoặc Ảnh động CSS:
element.animate([
{cssProperty: value0},
{cssProperty: value1},
{cssProperty: value2},
//...
], {
duration: timeInMs,
iterations: iterationCount,
delay: delayValue
});
Ưu điểm lớn nhất của hàm mới này là loại bỏ nhiều rào cản khó khăn mà trước đây chúng ta phải vượt qua để có được ảnh động mượt mà, không bị giật.
Ví dụ: đối với Santa Tracker năm ngoái, chúng tôi muốn tuyết rơi liên tục và quyết định tạo hiệu ứng động cho tuyết thông qua CSS để có thể thực hiện hiệu quả.
Tuy nhiên, chúng ta muốn chọn vị trí ngang của tuyết một cách linh động dựa trên màn hình và các sự kiện đang diễn ra trong chính cảnh đó, và tất nhiên, chiều cao của tuyết rơi (chiều cao của cửa sổ trình duyệt của người dùng) sẽ không được biết cho đến khi chúng ta thực sự chạy. Điều này có nghĩa là chúng ta thực sự phải sử dụng hiệu ứng chuyển đổi CSS, vì việc tạo ảnh động CSS trong thời gian chạy sẽ nhanh chóng trở nên phức tạp (và hàng trăm bông tuyết có nghĩa là hàng trăm quy tắc tạo kiểu mới).
Vì vậy, chúng tôi đã sử dụng phương pháp sau đây mà bạn chắc hẳn đã quen thuộc:
snowFlake.style.transform = 'translate(' + snowLeft + 'px, -100%)';
// wait a frame
snowFlake.offsetWidth;
snowFlake.style.transitionProperty = 'transform';
snowFlake.style.transitionDuration = '1500ms';
snowFlake.style.transform = 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)';
Điểm mấu chốt nằm ở nhận xét "wait a frame" (chờ một khung). Để bắt đầu chuyển đổi thành công, trình duyệt phải xác nhận rằng phần tử đang ở vị trí bắt đầu. Có một số cách để thực hiện việc này. Một trong những cách phổ biến nhất là đọc từ một trong các thuộc tính phần tử buộc trình duyệt tính toán bố cục, từ đó đảm bảo trình duyệt biết rằng phần tử có vị trí bắt đầu trước khi chuyển sang vị trí kết thúc. Khi sử dụng phương thức này, bạn có thể tự chúc mừng mình vì đã có kiến thức vượt trội về nội bộ trình duyệt, trong khi vẫn cảm thấy khó chịu với mỗi thao tác nhấn phím.
Ngược lại, lệnh gọi element.animate()
tương đương không thể rõ ràng hơn, cho biết chính xác ý định:
snowFlake.animate([
{transform: 'translate(' + snowLeft + 'px, -100%)'},
{transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
Còn nhiều tuỳ chọn khác. Giống như các đối tác CSS, Ảnh động trên web có thể bị trì hoãn và lặp lại:
snowFlake.animate([
{transform: 'translate(' + snowLeft + 'px, -100%)'},
{transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], {
duration: 1500,
iterations: 10,
delay: 300
});
AnimationPlayer
element.animate()
thực sự trả về một đối tượng AnimationPlayer. Đối tượng này sẽ trở nên ngày càng quan trọng khi có nhiều thông số kỹ thuật Ảnh động trên web được ra mắt. Cả ảnh động được tạo bằng JavaScript và CSS đều có AnimationPlayer được liên kết, cho phép kết hợp liền mạch theo những cách hữu ích và thú vị.
Tuy nhiên, hiện tại, AnimationPlayer chỉ có hai chức năng, cả hai đều rất hữu ích. Bạn có thể huỷ ảnh động bất cứ lúc nào bằng cách sử dụng AnimationPlayer.cancel()
:
var player = snowFlake.animate([
{transform: 'translate(' + snowLeft + 'px, -100%)'},
{transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
// less than 1500ms later...changed my mind
player.cancel();
Và để làm hài lòng tất cả những người đã từng cố gắng xây dựng một hệ thống ảnh động xoay quanh Ảnh động CSS hoặc Hiệu ứng chuyển đổi trong quá khứ, Ảnh động trên web luôn kích hoạt một sự kiện khi hoàn tất:
var player = snowFlake.animate([
{transform: 'translate(' + snowLeft + 'px, -100%)'},
{transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
player.onfinish = function(e) {
console.log('per aspera ad terra!');
}
Dùng thử
Tất cả những tính năng này đều có trong Chrome 36, sẽ chuyển sang phiên bản thử nghiệm beta từ hôm nay! Nếu bạn muốn dùng thử, hãy thử triển khai mã gốc trong Chrome 36. Tuy nhiên, có một polyfill Ảnh động trên web, giúp mang lại một phần lớn hơn đáng kể của thông số kỹ thuật đầy đủ về Ảnh động trên web cho bất kỳ trình duyệt hiện đại nào.
Bạn có thể dùng bản minh hoạ hiệu ứng tuyết để thử sử dụng cả phiên bản gốc của element.animate()
và polyfill.
Hãy cho chúng tôi biết suy nghĩ của bạn
Tuy nhiên, đây thực sự là bản xem trước về những tính năng sắp ra mắt và được phát hành riêng để nhận ý kiến phản hồi ngay lập tức từ nhà phát triển. Chúng tôi chưa chắc chắn liệu đã đáp ứng mọi trường hợp sử dụng hay chưa, hoặc đã xử lý mọi vấn đề còn tồn tại của các API hiện tại cho ảnh động hay chưa. Cách duy nhất để chúng tôi biết và thực sự làm đúng là nhà phát triển dùng thử và cho chúng tôi biết ý kiến của họ.
Tất nhiên, các nhận xét về bài đăng này rất có giá trị và bạn có thể gửi nhận xét về chính tiêu chuẩn này cho Nhóm làm việc về CSS và SVG thông qua danh sách gửi thư public-fx.
Nội dung cập nhật tháng 10 năm 2014: Chrome 39 hỗ trợ thêm một số phương thức khác liên quan đến việc kiểm soát chế độ phát, chẳng hạn như play()
, pause()
và reverse()
. Phương thức này cũng hỗ trợ chuyển đến một điểm cụ thể trong tiến trình của ảnh động thông qua thuộc tính currentTime
. Bạn có thể xem chức năng này hoạt động trong bản minh hoạ mới này.
Cảm ơn Addy Osmani và Max Heinritz đã hỗ trợ tôi viết bài đăng này.