Thời gian chính xác với API hoạt hình web

theanh

Administrator
Nhân viên
Trước đây, tôi coi hoạt ảnh là thứ gì đó vui tươi. Thứ gì đó làm giao diện trở nên mờ ảo. Ngoài ra, trong tay những người giỏi, hoạt ảnh có thể làm giao diện rõ ràng hơn. Một đặc tính của hoạt ảnh trên Web mà tôi không nghe nói nhiều là độ chính xác của chúng. API hoạt ảnh web cho phép chúng ta loại bỏ các giải pháp tạm thời liên quan đến các vấn đề về thời gian của JavaScript. Trong bài viết này, bạn sẽ thấy cách không nên thực hiện hoạt ảnh và cách phối hợp hoạt ảnh của nhiều thành phần.

Khi bạn làm việc trên bản trình bày trực quan về thứ gì đó đòi hỏi phải chính xác, bạn sẽ nhanh chóng nhận ra rằng mình dành quá nhiều thời gian để giải quyết vấn đề JavaScript không thể chính xác về thời điểm mã thực sự được thực thi. Hãy thử triển khai thứ gì đó dựa trên nhịp điệu hoặc thời gian chia sẻ và bạn sẽ hiểu ý tôi. Bạn có thể gần đạt được mục tiêu trong một số trường hợp nhưng không bao giờ hoàn hảo.

Một trong những điều tôi thấy hữu ích khi giải quyết các vấn đề phức tạp là chia nhỏ chúng thành các vấn đề nhỏ hơn, đơn giản hơn. Đôi khi các phần nhỏ hơn — ngay cả khi rất nhiều — có thứ gì đó thống nhất chúng. Một thứ gì đó cho phép bạn xử lý chúng một cách thống nhất. Trong trường hợp hoạt ảnh, giờ bạn phải xử lý nhiều thành phần hơn, bạn cần thứ gì đó đảm bảo mức độ chính xác về thời gian để loại trừ khả năng trôi, khả năng các thành phần "lệch nhịp".

Trước tiên, hãy xem điều gì có thể xảy ra với các công cụ thông thường mà JavaScript cung cấp.

Các vấn đề về thời gian của JavaScript: Đúng thứ tự nhưng lệch nhịp​

Trong JavaScript, mọi tác vụ đều phải trải qua một hàng đợi. Mã của bạn, tương tác của người dùng, sự kiện mạng. Mỗi tác vụ chờ đến lượt mình để được thực hiện bởi một vòng lặp sự kiện. Theo cách đó, nó đảm bảo rằng mọi thứ diễn ra theo thứ tự: khi bạn gọi một hàm, bạn có thể chắc chắn rằng không có chuyển động chuột đột ngột nào tự chèn vào giữa. Khi bạn cần mọi thứ diễn ra sau đó, bạn có thể đăng ký trình lắng nghe sự kiện hoặc bộ hẹn giờ.

Khi sự kiện kích hoạt hoặc bộ hẹn giờ đến hạn, tác vụ bạn đã xác định trong lệnh gọi lại sẽ được đưa vào hàng đợi. Khi vòng lặp sự kiện đến được, mã của bạn sẽ được thực thi. Đây là một khái niệm mạnh mẽ cho phép chúng ta bỏ qua hầu hết tính đồng thời. Nó hoạt động tốt, nhưng bạn nên hiểu rõ cách thức hoạt động của nó.

Chúng ta sẽ xem xét hậu quả của việc này trong bối cảnh hoạt hình. Tôi khuyến khích bạn tìm hiểu sâu hơn về chủ đề này. Hiểu được bản chất hoạt động của JavaScript sẽ giúp bạn tiết kiệm thời gian và giữ màu tóc. Jake Archibald đã làm rất tốt khi phân tích tất cả trong bài viết “Nhiệm vụ, Nhiệm vụ nhỏ, Hàng đợi và Lịch trình” và gần đây hơn là trong bài nói chuyện “In The Loop” tại JSConf.

Sau đây là những gì đang chờ bạn sau khi quyết định thực hiện hoạt ảnh với setTimeout hoặc setInteval:
  • Độ chính xác thấp
  • Pile Ups
  • Crowded Hàng đợi

Độ chính xác thấp​

Chúng ta có thể xác định chính xác thời gian chờ trước khi đưa tác vụ của mình vào hàng đợi. Điều chúng ta không thể dự đoán là những gì sẽ có trong hàng đợi tại thời điểm đó. Có thể triển khai bộ hẹn giờ tự điều chỉnh bằng cách kiểm tra sự khác biệt giữa độ dài tích tắc đã lên kế hoạch và thời điểm thực tế mà mã được thực thi. Sự khác biệt đó được áp dụng cho thời gian chờ tích tắc tiếp theo.

Phần lớn là hiệu quả, nhưng nếu khoảng cách cần thiết giữa các tích tắc được đo bằng hai chữ số mili giây hoặc ít hơn, thì nó hiếm khi đạt đúng thời điểm. Ngoài ra, bản chất của nó (điều chỉnh khi thực thi) khiến việc hình dung ra một thứ gì đó có nhịp điệu trở nên khó khăn. Nó sẽ hiển thị trạng thái chính xác khi nó được gọi, nhưng không phải thời điểm chính xác mà trạng thái đã thay đổi.

Đó là vì setTimeout đảm bảo độ trễ tối thiểu trước khi một thứ được đưa vào hàng đợi. Nhưng không có cách nào để biết những gì sẽ có trong hàng đợi.

Pile Ups​

Nếu độ chính xác thấp đôi khi ổn với bạn, bạn sẽ nhận được một đống. Những thứ bạn muốn được giãn cách theo thời gian có thể được thực hiện cùng một lúc nếu có nhiều tác vụ để vòng lặp sự kiện xử lý — hoặc tất cả có thể bị tạm dừng.

Những tiến bộ về thời lượng pin đi kèm với phần cứng tốt hơn và phần mềm hiệu quả hơn. Các tab trình duyệt có thể bị tạm dừng để giảm mức tiêu thụ điện năng khi không sử dụng. Khi các tab được lấy nét trở lại, vòng lặp sự kiện có thể thấy mình có một số lệnh gọi lại — một số trong số đó được phát hành bởi bộ hẹn giờ — trong hàng đợi để xử lý.

Có lần tôi phải triển khai việc lật ngẫu nhiên các ô cho một trang web và một trong những lỗi là do các tab đang ngủ gây ra. Vì mỗi ô duy trì bộ hẹn giờ riêng nên tất cả chúng đều được kích hoạt đồng thời khi tab hoạt động.

Lưu ý cách các khối hàng trên cùng bị trì hoãn rồi lật ba khối cùng một lúc. (Xem Pen [CodePen Home Timeouts so với DocumentTimeline](https://codepen.io/smashingmag/pen/BaYVLGo) của Kirill Myshkin)
Lưu ý cách các khối hàng trên cùng bị trì hoãn rồi lật ba khối cùng một lúc. (Xem Pen CodePen Home Timeouts so với DocumentTimeline của Kirill Myshkin)

Crowded Queue​

Có khả năng là mã của bạn đã bị hạn chế bởi các thư viện và khung. Điều đó có nghĩa là các lệnh gọi lại từ bộ đếm thời gian của bạn có nhiều khả năng được đưa vào hàng đợi tại một thời điểm không may. Bạn có thể không có nhiều cơ hội để tối ưu hóa vì đã có quá nhiều mã chạy xung quanh.

Những thiếu sót trên có thể được giải quyết trong một số trường hợp nhất định. Bạn tự quyết định điều gì có giá trị hơn trong từng dự án cụ thể. Nếu tất cả các thành phần của bạn có thể được quản lý bởi một bộ đếm thời gian duy nhất, bạn có thể làm cho nó hoạt động.

Tuy nhiên, tôi sẽ xem xét requestAnimationFrame thay vì bộ đếm thời gian để quản lý hoạt ảnh. Bài nói chuyện của Jake mà tôi đã liên kết ở trên minh họa điều này một cách tuyệt vời. Điều mà nó mang lại cho bạn là nhịp điệu. Bạn có thể chắc chắn rằng mã của bạn sẽ được thực thi ngay trước khi người dùng có thể nhìn thấy bất cứ điều gì. Vì bạn có dấu thời gian về thời điểm hàm của mình được gọi, bạn có thể sử dụng dấu thời gian đó để tính toán trạng thái chính xác mà bạn cần có.

Tùy thuộc vào bạn, điều gì đáng để bạn dành thời gian giải quyết. Có thể một giải pháp thay thế cụ thể là ổn và bạn có thể tiếp tục với bất kỳ giải pháp nào bạn đang cố gắng triển khai. Bạn là người đánh giá tốt hơn về những gì hiệu quả trong trường hợp của mình.

Nếu điều bạn đang cố gắng triển khai phù hợp với lĩnh vực hoạt ảnh, bạn sẽ được hưởng lợi khi di chuyển nó ra khỏi hàng đợi. Hãy cùng xem cách chúng ta đến được nơi mà thời gian là vua.

Web Animations API: Nơi mọi thứ đồng bộ​

Trong bài viết trước của tôi, "Điều phối sự phức tạp với Web Animations API", chúng ta đã xem xét các cách để làm cho một số hoạt ảnh có thể kiểm soát được như thể chúng là một. Bây giờ chúng ta sẽ xem xét cách đảm bảo rằng tất cả các hoạt ảnh của bạn bắt đầu vào đúng thời điểm.

Dòng thời gian​

Web Animations API giới thiệu một khái niệm về dòng thời gian. Theo mặc định, tất cả các hoạt ảnh đều được liên kết với dòng thời gian của tài liệu. Điều đó có nghĩa là các hoạt ảnh chia sẻ cùng một "đồng hồ bên trong" — một đồng hồ bắt đầu khi tải trang.

Đồng hồ được chia sẻ đó là thứ cho phép chúng ta phối hợp các hoạt ảnh. Cho dù đó là nhịp điệu hay mẫu nhất định, bạn không cần phải lo lắng rằng một thứ gì đó sẽ kéo dài hoặc vượt quá chính nó.

Thời gian bắt đầu​

Để bắt đầu hoạt ảnh tại một thời điểm nhất định, bạn sử dụng thuộc tính startTime. Giá trị của startTime được đo bằng mili giây từ khi tải trang. Hoạt ảnh có thời gian bắt đầu được đặt thành 1000.5 sẽ bắt đầu phát lại chính xác khi thuộc tính currentTime của dòng thời gian tài liệu bằng 1000.5.

Bạn có để ý dấu chấm trong giá trị thời gian bắt đầu không? Đúng vậy, bạn có thể sử dụng phân số của mili giây, chính xác như vậy đấy. Tuy nhiên, độ chính xác chính xác phụ thuộc vào cài đặt trình duyệt.

Một điều hữu ích khác là thời gian bắt đầu cũng có thể là số âm. Bạn có thể tùy ý đặt thành một thời điểm trong tương lai hoặc một thời điểm trong quá khứ. Đặt giá trị thành -1000 và trạng thái hoạt ảnh của bạn sẽ giống như đã được phát trong một giây khi trang tải. Đối với người dùng, có vẻ như hoạt ảnh đã bắt đầu phát trước khi họ thậm chí nghĩ đến việc truy cập trang của bạn.

Lưu ý: Lưu ý rằng timelinestartTime vẫn là các công nghệ thử nghiệm.

Bản demo​

Để chứng minh cách bạn có thể sử dụng nó, tôi đã thiết lập một bản demo. Tôi đã triển khai một chỉ báo phụ thuộc vào độ chính xác của thời gian hơn bất kỳ chỉ báo nào khác — một chiếc đồng hồ. Tôi đã triển khai hai chỉ báo, theo cách đó, một chỉ báo sẽ tiết lộ sự tuyệt vời của chỉ báo kia. Một số điều trong bản demo này đủ đơn giản để chứng minh những điều cơ bản. Ngoài ra còn có một số phần khó khăn cho bạn thấy cách tiếp cận này còn thiếu sót ở đâu.

Đồng hồ kỹ thuật số và đồng hồ analog, cả hai đều được triển khai kỹ thuật số. (Xem Pen [Clock](https://codepen.io/smashingmag/pen/BaYVLMj) của Kirill Myshkin)
Đồng hồ kỹ thuật số và đồng hồ analog, cả hai đều được triển khai kỹ thuật số. (Xem Pen Đồng hồ của Kirill Myshkin)
Chuyển động của đồng hồ analog khá đơn giản. Ba kim thực hiện cùng một vòng quay một vòng — khá lạc quan — vô số lần. Vì đồng hồ là một công cụ chính xác, tôi đã làm cho kim giây và kim phút thay đổi vị trí của chúng tại thời điểm chính xác mà các giá trị tương ứng của chúng thay đổi. Điều đó giúp minh họa rằng chúng thay đổi tại thời điểm chính xác như những người anh em họ của chúng trên đồng hồ kỹ thuật số bên dưới.
Mã:
const clock = document.getElementById("analog-clock");const second = clock.querySelector(".second");const minute = clock.querySelector(".minute");const hour = clock.querySelector(".hour");const s = 1000;const m = s * 60;const h = m * 60;const d = h * 24;const hands = [second, minute, hour];const hand_durations = [m, h, d];const steps = [60, 60, 120];const movement = hands.map(function (hand, index) { return hand.animate( [ {transform: "rotate(0turn)"}, {transform: "rotate(1turn)"} ], { duration: hand_durations[index], iterations: Infinity, easing: `steps(${steps[index]}, end)` } );});movement.forEach(function (move) { move.startTime = start_time;});
Hoạt ảnh cho mỗi trong ba kim khác nhau về thời gian quay và số bước chia. Kim giây quay một vòng trong sáu mươi nghìn mili giây. Kim phút quay chậm hơn sáu mươi lần. Kim giờ — vì nó là đồng hồ hai mươi bốn giờ — thực hiện một vòng trong thời gian bằng với thời gian kim phút thực hiện hai mươi bốn vòng.

Để liên kết hoạt động của kim đồng hồ với cùng một khái niệm về thời gian (để đảm bảo kim phút cập nhật vị trí của nó chính xác tại thời điểm kim giây hoàn thành vòng quay của nó), tôi đã sử dụng thuộc tính startTime. Tất cả các hoạt ảnh trong bản demo này đều được đặt thành cùng một thời gian bắt đầu. Và đó là tất cả những gì bạn cần. Đừng lo lắng về hàng đợi, tab bị treo hoặc hàng đống thời gian chờ. Chỉ cần định nghĩa một lần là xong.

Mặt khác, đồng hồ kỹ thuật số hơi phản trực giác. Mỗi chữ số là một hộp chứa có overflow: hidden;. Bên trong, có một hàng số từ không đến một nằm trong các ô có chiều rộng bằng nhau. Mỗi chữ số được hiển thị bằng cách dịch chuyển hàng theo chiều ngang theo chiều rộng của một ô nhân với giá trị chữ số. Giống như kim đồng hồ analog, vấn đề là phải thiết lập đúng thời lượng cho mỗi chữ số. Trong khi tất cả các chữ số từ mili giây đến phút đều dễ thực hiện, thì giờ lại cần một số thủ thuật — tôi sẽ đề cập bên dưới.

Hãy xem giá trị của biến start_time:
Mã:
const start_time = (function () { const time = new Date(); const hour_diff = time.getHours() - time.getUTCHours(); const my_current_time = (Number(time) % d) + (hour_diff * h); return document.timeline.currentTime - my_current_time;}());
Để tính toán thời điểm chính xác mà tất cả các phần tử phải bắt đầu (tức là sau nửa đêm), tôi đã lấy giá trị của Date.now() (mili giây kể từ ngày 1 tháng 1 năm 1970), loại bỏ toàn bộ ngày khỏi giá trị đó và điều chỉnh theo chênh lệch với giờ UTC. Điều đó giúp tôi có được số mili giây đã trôi qua kể từ đầu ngày hôm nay. Đây là dữ liệu duy nhất mà đồng hồ của tôi cần để hiển thị những gì nó được định sẵn để hiển thị: giờ, phútgiây.

Để chuyển đổi giá trị đó sang phạm vi của tài liệu, tôi cần điều chỉnh giá trị đó dựa trên thời gian đã trôi qua kể từ khi tải trang demo này cho đến khi gọi Date.now(). Để thực hiện điều đó, tôi đã trừ nó khỏi currentTime của tài liệu. Áp dụng kết quả cho một hoạt ảnh có nghĩa là hoạt ảnh cụ thể này đã phát từ nửa đêm. Áp dụng điều đó cho tất cả các hoạt ảnh và bạn sẽ có một bản demo đã phát từ nửa đêm.

Về mặt lý thuyết, chúng ta có thể có một chiếc đồng hồ chạy từ ngày 1 tháng 1 năm 1970 (52 năm tính đến thời điểm viết bài này), nhưng một số trình duyệt có giới hạn không được ghi lại về giá trị thời lượng của hoạt ảnh. Cũng sẽ hợp lý khi áp dụng một số CSS để làm cũ đồng hồ như vậy một cách nhân tạo — vì sẽ không có sự khác biệt nào khác so với đồng hồ đã chạy từ đêm qua. Cả hai đồng hồ đó sẽ đồng bộ hoàn hảo.

Những thiếu sót của phương pháp này​

Thật tuyệt vời khi có thể triển khai thứ gì đó có độ chính xác như vậy mà không cần bất kỳ phép tính phức tạp nào. Nhưng nó chỉ hiệu quả trong những trường hợp mà những thứ bạn đang cố gắng triển khai có thể được xác định bằng khung hình chính. Bạn nên quyết định, dựa trên trường hợp cụ thể của mình, nơi nào sẽ có lợi và nơi nào sẽ trở nên cồng kềnh và tốn kém hơn khi xử lý những thiếu sót.

Một giải pháp thay thế cho Web Animations API là sử dụng requestAnimationFrame hoặc performance.now(). Với những giải pháp đó, bạn sẽ cần tự tính toán nội suy.

Nếu bạn chọn dựa vào Web Animations API, bạn sẽ phải đối mặt với thực tế là những thứ phù hợp khác nhau với định nghĩa khung hình chính. Một số thứ có thể hầu như không mất công để xác định vì chúng phù hợp một cách tự nhiên. Những thứ khác đòi hỏi phải có giải pháp thay thế. Việc những giải pháp thay thế đó có làm tăng thêm nhiều chi phí hay không đối với những gì bạn đang cố gắng triển khai sẽ quyết định cách tiếp cận của bạn.

Bản demo đồng hồ có ví dụ về cả hai trường hợp. Bản thân kim đồng hồ là thứ dễ làm nhất. Đây là khung hình chính của một vòng quay với chức năng gia tốc steps để khiến chúng tích tắc. Cuối cùng, chuyển động chính của đồng hồ demo hầu như không mất công sức. Tôi ước mình có thể nói rằng đồng hồ kỹ thuật số dễ triển khai như vậy. Nhưng tôi cho rằng đó là do những thiếu sót của riêng tôi.

Có ba ví dụ về giải pháp thay thế mà tôi phải quay lại. Tôi hy vọng chúng sẽ giúp bạn hình dung được những gì bạn có thể cần làm nếu bạn sử dụng phương pháp hoạt ảnh. Chúng không phải là đại diện tốt cho giới hạn của API Hoạt ảnh Web, chúng chỉ cho thấy cách triển khai cụ thể mà tôi đã chọn phải được thay đổi để phù hợp. Hãy cùng xem tôi phải làm thêm những công việc nào.

Một số Thuộc tính sẽ không Hoạt ảnh Như Bạn Muốn​

Nếu bạn nhìn kỹ, mỗi kim trên đồng hồ analog đều có bóng đổ. Chúng tạo thêm chiều sâu và làm cho đồng hồ trông đẹp hơn. Bóng đổ dễ dàng được áp dụng bằng các thuộc tính CSS box-shadow hoặc filter. Nó có thể hoạt hình ở một mức độ nào đó, nhưng nó không hoạt hình ở hướng bóng đổ. Bạn không thiết lập nó bằng giá trị góc mà bằng tọa độ.

Tôi không thể tìm ra cách để triển khai chuyển động tròn của bóng đổ bằng hai tọa độ. Thay vào đó, tôi chia nhỏ mỗi bàn tay thành ba phần tử hoạt hình riêng biệt (xem bài viết trước của tôi "Sắp xếp độ phức tạp bằng API hoạt hình web" để biết kỹ thuật đó). Phần đầu tiên là một lớp bao bọc chứa hai phần khác của bàn tay: thân và bóng đổ. Lớp bao bọc là phần tử mà vòng quay chính được áp dụng. Thân xác định hình dạng, kích thước và màu sắc của bàn tay, trong khi bóng đổ sao chép các thuộc tính của thân (trừ màu sắc). Thêm vào đó, nó có hoạt ảnh riêng được xác định — nó xoay quanh tâm bàn tay.

Việc nhân số lượng phần tử cần xử lý có vẻ khó thực hiện hơn. Tuy nhiên, trong trường hợp của bóng đổ, thực tế là cuối cùng nó đã được tách ra khỏi bàn tay đã mang lại sự linh hoạt hơn. Bạn có thể định dạng nó bằng cách sử dụng CSS. Và vì thời gian đã được xử lý, nên việc có nhiều phần tử hơn không làm cho nó khó hơn.

Phép chia không phải lúc nào cũng dẫn đến các phần chia bằng nhau​

Giải pháp thay thế thứ hai là cần thiết cho phần giờ của đồng hồ kỹ thuật số. Đồng hồ được triển khai với các phần tử một chữ số. Ba phần tử cho mili giây, hai phần tử cho giây và hai phần tử cho phút. Các chữ số giờ không phù hợp với logic của khung hình chính lặp lại.

Các vòng lặp không đều đặn vì chỉ có bốn giờ trong thập niên hai mươi. Tôi đã phải giới thiệu một chữ số "rộng" để giải quyết vấn đề này. Chữ số rộng có cùng logic như một chữ số bình thường, chỉ là nó hỗ trợ các số từ không đến chín mươi chín — đủ cho trường hợp này. Cuối cùng, kim chỉ giờ của đồng hồ kỹ thuật số đã sử dụng lại cùng tùy chọn thời gian như kim giờ trên đồng hồ analog.

Bạn không bao giờ biết tháng tới sẽ dài bao lâu nếu không kiểm tra Lịch​

Giải pháp thứ ba là cho biến chứng ngày tháng. Bây giờ tôi đã có phần tử chữ số "rộng", tôi đã sử dụng lại nó để hiển thị ngày tháng và chỉ tăng thời lượng từ giờ lên ngày.

Vấn đề với cách tiếp cận đó là độ dài tháng không khớp hoàn hảo với cùng độ dài hoạt ảnh được sử dụng trong bản demo. Bạn thấy đấy, lịch mà chúng ta sử dụng ngày nay có lịch sử lộn xộn và khó có thể đưa vào một vòng lặp đơn giản. Người ta sẽ phải xác định tất cả các trường hợp ngoại lệ của lịch Gregory trong một khung hình chính duy nhất. Tôi sẽ bỏ qua việc đó. Tôi ở đây để chỉ cho bạn một giải pháp.

Tôi đã chọn dựa vào Ngày thay vì xác định thêm một lịch lỗi nữa. Ai biết được những tháng trong tương lai sẽ có bao nhiêu ngày, phải không?
Mã:
hàm month() { const now = new Date(); return digits( (new Date(now.getFullYear(), now.getMonth() + 1, 0)).getDate(), false );}hàm create_animation(digit) { const nr_digits = digit.firstElementChild.children.length; const duration = d * nr_digits; trả về digit.firstElementChild.animate( [ {transform: "translateX(0)"}, {transform: "translateX(calc(var(--len) * -2ch)"} ], { duration, easing: `steps(${nr_digits}, end)`, iterationStart: (d * ((new Date()).getDate() - 1)) / duration } );}(function set_up_date_complication() { const day = document.querySelector(".day"); const new_day = day.cloneNode(); new_day.append(month()); day.replaceWith(new_day); Array.from(new_day.children).forEach(function (digit) { const complication = create_animation(digit); complication.startTime = start_time; complication.finished.then(set_up_date_complication); });}());
Để tạo sự phức tạp về ngày bulletproof, tôi đã định nghĩa thời lượng của nó là độ dài của tháng hiện tại. Để tiếp tục sử dụng cùng một thời gian bắt đầu và tránh giới hạn về giá trị duration, chúng ta "tua lại" hoạt ảnh về đúng ngày bằng thuộc tính iterationStart.

Khi tháng kết thúc, chúng ta cần xây dựng lại biến chứng ngày cho tháng tiếp theo. Thời điểm thích hợp để làm điều đó là khi hoạt ảnh biến chứng kết thúc. Không giống như các hoạt ảnh khác trong bản demo này, ngày không lặp lại, vì vậy chúng ta sẽ tạo một ngày mới bằng cách sử dụng lời hứa finished của hoạt ảnh tháng hiện tại.

Cách tiếp cận đó gặp phải những thiếu sót được mô tả ở đầu bài viết này. Nhưng trong trường hợp của các tháng, chúng ta có thể nhắm mắt làm ngơ trước sự thiếu chính xác nhỏ.

Bạn sẽ phải tin lời tôi nói rằng nó hiệu quả. Nếu không, hãy quay lại bài viết này vào bất kỳ ngày cuối cùng nào của tháng gần nửa đêm. Ai biết được, bạn có thể thấy tôi trên cùng một trang, với đôi mắt tràn đầy hy vọng và những ngón tay bắt chéo.

Kết luận​

Hoạt ảnh chia sẻ cùng một tham chiếu thời gian và bằng cách điều chỉnh thuộc tính startTime của chúng, bạn có thể căn chỉnh chúng theo bất kỳ mẫu nào bạn cần. Bạn có thể chắc chắn rằng chúng sẽ không trôi.

API Hoạt ảnh Web đi kèm với các công cụ mạnh mẽ cho phép bạn giảm đáng kể lượng công việc mà ứng dụng của bạn và bạn phải làm. Nó cũng đi kèm với độ chính xác mở ra khả năng triển khai các loại ứng dụng mới.

Sức mạnh đó nằm trong lĩnh vực hoạt ảnh. Việc nó có phù hợp với trường hợp của bạn hay không là điều bạn quyết định dựa trên nhu cầu của mình. Tôi hy vọng các ví dụ tôi cung cấp trong bài viết này sẽ giúp bạn hiểu rõ hơn về con đường nên chọn.

Đọc thêm​

  • “Orchestrating Complexity With Web Animations API,” Kirill Myshkin
  • “Understanding Easing Functions For CSS Animations And Transitions,” Adrian Bece
  • “Practical Techniques On Designing Animation,” Sarah Drasner
  • “Designing With Reduced Motion For Motion Sensitivities,” Val Head
 
Back
Bên trên