Hack trạng thái hoạt ảnh CSS và thời gian phát lại PlatoBlockchain Data Intelligence. Tìm kiếm dọc. Ái.

Hacking CSS trạng thái hoạt ảnh và thời gian phát lại

Wolfenstein chỉ có CSS là một dự án nhỏ mà tôi đã thực hiện cách đây vài tuần. Đó là một thử nghiệm với các hình ảnh động và chuyển đổi CSS 3D.

Lấy cảm hứng từ Bản trình diễn FPS và khác Mã WolfensteinBút, Tôi quyết định xây dựng phiên bản của riêng mình. Nó dựa trên Tập 1 - Tầng 9 của trò chơi Wolfenstein 3D gốc.

Biên tập viên: Trò chơi này cố ý yêu cầu một số phản ứng nhanh để tránh màn hình Game Over.

Đây là một video phát qua:

[Nhúng nội dung]

Tóm lại, dự án của tôi không có gì khác ngoài một hoạt ảnh CSS dài được viết kịch bản cẩn thận. Cộng với một số trường hợp của hack hộp kiểm.

:checked ~ div { animation-name: spin; }

Môi trường bao gồm các mặt lưới 3D và các hình ảnh động chủ yếu là các bản dịch và phép quay 3D đơn giản. Không có gì thực sự ưa thích.

Tuy nhiên, có hai vấn đề đặc biệt khó giải quyết:

  • Phát hoạt ảnh "bắn vũ khí" bất cứ khi nào người chơi nhấp vào kẻ thù.
  • Khi tên trùm di chuyển nhanh nhận được cú đánh cuối cùng, hãy nhập một chuyển động chậm đầy ấn tượng.

Ở cấp độ kỹ thuật, điều này có nghĩa là:

  • Phát lại hoạt ảnh khi hộp kiểm tiếp theo được chọn.
  • Làm chậm hoạt ảnh khi hộp kiểm được chọn.

Trong thực tế, cả hai đều không được giải quyết đúng cách trong dự án của tôi! Tôi hoặc cuối cùng đã sử dụng các giải pháp thay thế hoặc chỉ từ bỏ.

Mặt khác, sau một số lần đào sâu, cuối cùng tôi đã tìm ra chìa khóa cho cả hai vấn đề: thay đổi các thuộc tính của hoạt ảnh CSS đang chạy. Trong bài viết này, chúng ta sẽ tìm hiểu sâu hơn về chủ đề này:

  • Rất nhiều ví dụ tương tác.
  • Mổ xẻ: làm thế nào để mỗi ví dụ hoạt động (hoặc không hoạt động)?
  • Hậu trường: trình duyệt xử lý trạng thái hoạt ảnh như thế nào?

Để tôi "Ném gạch của tôi".

Vấn đề 1: Phát lại hoạt ảnh

Ví dụ đầu tiên: “chỉ là một hộp kiểm khác”

Trực giác đầu tiên của tôi là "chỉ cần thêm một hộp kiểm khác", hộp kiểm này không hoạt động:

Mỗi hộp kiểm hoạt động riêng lẻ, nhưng không hoạt động cả hai cùng nhau. Nếu một hộp kiểm đã được chọn, hộp kiểm kia không còn hoạt động nữa.

Đây là cách nó hoạt động (hoặc "không hoạt động"):

  1. Sản phẩm animation-name of <div> is none theo mặc định.
  2. Người dùng nhấp vào một hộp kiểm, animation-name trở thành spin, và hoạt ảnh bắt đầu từ đầu.
  3. Sau một lúc, người dùng nhấp vào hộp kiểm khác. Quy tắc CSS mới có hiệu lực, nhưng animation-name is vẫn còn spin, có nghĩa là không có hoạt ảnh nào được thêm vào cũng như bị loại bỏ. Hoạt ảnh chỉ đơn giản là tiếp tục phát như thể không có gì xảy ra.

Ví dụ thứ hai: “nhân bản hoạt ảnh”

Một cách tiếp cận hiệu quả là sao chép hoạt ảnh:

#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2; }

Dưới đây là cách hoạt động:

  1. animation-name is none ban đầu
  2. Người dùng nhấp vào “Spin!”, animation-name trở thành spin1. Các hình ảnh động spin1 được bắt đầu từ đầu vì nó mới được thêm vào.
  3. Người dùng nhấp vào “Quay lại!”, animation-name trở thành spin2. Các hình ảnh động spin2 được bắt đầu từ đầu vì nó mới được thêm vào.

Lưu ý rằng trong Bước # 3, spin1 bị xóa do thứ tự của các quy tắc CSS. Nó sẽ không hoạt động nếu "Quay lại!" được kiểm tra đầu tiên.

Ví dụ thứ ba: “nối cùng một hoạt ảnh”

Một cách tiếp cận hiệu quả khác là "nối cùng một hoạt ảnh":

#spin1:checked ~ div { animation-name: spin; }
#spin2:checked ~ div { animation-name: spin, spin; }

Điều này tương tự với ví dụ trước. Bạn thực sự có thể hiểu hành vi theo cách này:

#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2, spin1; }

Lưu ý rằng khi "Quay lại!" được chọn, hoạt ảnh cũ đang chạy sẽ trở thành hoạt ảnh thứ hai trong danh sách mới, có thể không trực quan. Hậu quả trực tiếp là: thủ thuật sẽ không hoạt động nếu animation-fill-mode is forwards. Đây là bản demo:

Nếu bạn tự hỏi tại sao lại như vậy, thì đây là một số manh mối:

  • animation-fill-mode is none theo mặc định, có nghĩa là "Hoạt ảnh không có tác dụng gì nếu không phát".
  • animation-fill-mode: forwards; có nghĩa là “Sau khi hoạt ảnh kết thúc phát, hoạt ảnh phải ở lại khung hình chính cuối cùng mãi mãi”.
  • spin1quyết định của luôn ghi đè spin2bởi vì spin1 xuất hiện sau trong danh sách.
  • Giả sử người dùng nhấp vào “Quay!”, Đợi một vòng quay đầy đủ, sau đó nhấp vào “Quay lại!”. Tại thời điểm này. spin1 đã hoàn thành, và spin2 chỉ mới bắt đầu.

Thảo luận

Quy tắc chung: bạn không thể “khởi động lại” hoạt ảnh CSS hiện có. Thay vào đó, bạn muốn thêm và phát một hoạt ảnh mới. Điều này có thể được xác nhận bởi thông số kỹ thuật W3C:

Khi hoạt ảnh đã bắt đầu, nó sẽ tiếp tục cho đến khi kết thúc hoặc tên-hoạt ảnh bị xóa.

Bây giờ so sánh hai ví dụ cuối cùng, tôi nghĩ trong thực tế, “hoạt ảnh nhân bản” thường hoạt động tốt hơn, đặc biệt là khi có sẵn bộ xử lý trước CSS.

Vấn đề 2: Chuyển động chậm

Người ta có thể nghĩ rằng làm chậm hoạt ảnh chỉ là vấn đề của việc thiết lập thời gian dài hơn animation-duration:

div { animation-duration: 0.5s; }
#slowmo:checked ~ div { animation-duration: 1.5s; }

Thật vậy, điều này hoạt động:

… Hay không?

Với một vài chỉnh sửa, bạn sẽ thấy vấn đề dễ dàng hơn.

Có, hoạt ảnh bị chậm lại. Và không, nó không đẹp. Con chó (hầu như) luôn "nhảy" khi bạn chuyển đổi hộp kiểm. Hơn nữa, con chó dường như nhảy đến một vị trí ngẫu nhiên hơn là vị trí ban đầu. Làm thế nào mà?

Sẽ dễ hiểu hơn nếu chúng tôi giới thiệu hai “yếu tố bóng tối”:

Cả hai yếu tố bóng đang chạy các hoạt ảnh giống nhau với các animation-duration. Và chúng không bị ảnh hưởng bởi hộp kiểm.

Khi bạn chuyển đổi hộp kiểm, phần tử chỉ ngay lập tức chuyển đổi giữa các trạng thái của hai phần tử bóng.

Trích dẫn thông số kỹ thuật W3C:

Các thay đổi đối với giá trị của thuộc tính hoạt ảnh trong khi hoạt ảnh đang chạy áp dụng như thể hoạt ảnh có các giá trị đó từ khi bắt đầu.

Điều này theo không quốc tịch thiết kế, cho phép trình duyệt dễ dàng xác định giá trị hoạt ảnh. Tính toán thực tế được mô tả tại đâytại đây.

Nỗ lực khác

Một ý tưởng là tạm dừng hoạt ảnh hiện tại, sau đó thêm một hoạt ảnh chậm hơn sẽ tiếp quản từ đó:

div {
  animation-name: spin1;
  animation-duration: 2s;
}

#slowmo:checked ~ div {
  animation-name: spin1, spin2;
  animation-duration: 2s, 5s;
  animation-play-state: paused, running;
}

Vì vậy, nó hoạt động:

… Hay không?

Nó sẽ chậm lại khi bạn nhấp vào “Slowmo!”. Nhưng nếu bạn đợi một vòng tròn đầy đủ, bạn sẽ thấy một "bước nhảy". Trên thực tế, nó luôn nhảy đến vị trí khi “Slowmo!” được nhấp vào.

Lý do là chúng tôi không có from keyframe được xác định - và chúng ta không nên làm như vậy. Khi người dùng nhấp vào “Slowmo!”, spin1 bị tạm dừng ở một số vị trí, và spin2 bắt đầu ở chính xác cùng một vị trí. Đơn giản là chúng ta không thể đoán trước vị trí đó… hay có thể không?

Một giải pháp làm việc

Chúng ta có thể! Bằng cách sử dụng thuộc tính tùy chỉnh, chúng ta có thể chụp góc trong hoạt ảnh đầu tiên, sau đó chuyển nó sang hoạt ảnh thứ hai:

div {
  transform: rotate(var(--angle1));
  animation-name: spin1;
  animation-duration: 2s;
}

#slowmo:checked ~ div {
  transform: rotate(var(--angle2));
  animation-name: spin1, spin2;
  animation-duration: 2s, 5s;
  animation-play-state: paused, running;
}

@keyframes spin1 {
  to {
    --angle1: 360deg;
  }
}

@keyframes spin2 {
  from {
    --angle2: var(--angle1);
  }
  to {
    --angle2: calc(var(--angle1) + 360deg);
  }
}

Lưu ý: @property được sử dụng trong ví dụ này, đó là không được hỗ trợ bởi tất cả các trình duyệt.

Giải pháp "Hoàn hảo"

Có một cảnh báo cho giải pháp trước đó: "thoát slowmo" không hoạt động tốt.

Đây là một giải pháp tốt hơn:

Trong phiên bản này, chuyển động chậm có thể được nhập hoặc thoát liền mạch. Không có tính năng thử nghiệm nào được sử dụng. Vậy nó có phải là giải pháp hoàn hảo? Có và không.

Giải pháp này hoạt động giống như “chuyển số” “bánh răng”:

  • Gears: có hai <div>S. Một người là cha mẹ của người kia. Cả hai đều có spin hoạt hình nhưng với khác animation-duration. Trạng thái cuối cùng của phần tử là sự tích lũy của cả hai hình ảnh động.
  • Dịch chuyển: Lúc đầu, chỉ có một <div> có hoạt ảnh của nó đang chạy. Cái kia bị tạm dừng. Khi hộp kiểm được bật, cả hai hoạt ảnh sẽ hoán đổi trạng thái của chúng.

Trong khi tôi thực sự thích kết quả, có một vấn đề: đó là một cách khai thác tốt spin hoạt ảnh, không hoạt động với các loại hoạt ảnh khác nói chung.

Một giải pháp thực tế (với JS)

Đối với các hoạt ảnh chung, có thể đạt được chức năng chuyển động chậm bằng một chút JavaScript:

Giải thích nhanh:

  • Thuộc tính tùy chỉnh được sử dụng để theo dõi tiến trình hoạt ảnh.
  • Hoạt ảnh được "khởi động lại" khi hộp kiểm được chuyển đổi.
  • Mã JS tính đúng animation-delay để đảm bảo quá trình chuyển đổi liền mạch. Tôi đề nghị bài viết này nếu bạn không quen thuộc với các giá trị âm của animation-delay.

Bạn có thể xem giải pháp này là sự kết hợp giữa phương pháp “khởi động lại hoạt ảnh” và phương pháp “sang số”.

Ở đây, điều quan trọng là phải theo dõi tiến trình hoạt ảnh một cách chính xác. Các giải pháp thay thế có thể thực hiện được nếu @property không có sẵn. Ví dụ, phiên bản này sử dụng z-index để theo dõi tiến trình:

Lưu ý: ban đầu, tôi cũng đã cố gắng tạo một phiên bản chỉ dành cho CSS nhưng không thành công. Mặc dù không chắc chắn 100%, nhưng tôi nghĩ đó là vì animation-delay is không hoạt hình.

Đây là một phiên bản với JavaScript tối thiểu. Chỉ "nhập slowmo" mới hoạt động.

Vui lòng cho tôi biết nếu bạn muốn tạo phiên bản chỉ CSS hoạt động!

Chuyển động chậm Mọi hoạt ảnh (với JS)

Cuối cùng, tôi muốn chia sẻ một giải pháp hoạt động cho (hầu hết) bất kỳ hoạt ảnh nào, ngay cả với nhiều @keyframes:

Về cơ bản, bạn cần thêm trình theo dõi tiến trình hoạt ảnh, sau đó tính toán cẩn thận animation-delay cho hoạt ảnh mới. Tuy nhiên, đôi khi có thể khó (nhưng có thể) để có được các giá trị chính xác.

Ví dụ:

  • animation-timing-function không phải là linear.
  • animation-direction không phải là normal.
  • nhiều giá trị trong animation-name có khác nhau animation-duration'cát animation-delay'S.

Phương pháp này cũng được mô tả tại đây cho API hoạt ảnh trên web.

Lời cảm ơn

Tôi bắt đầu đi theo con đường này sau khi gặp các dự án chỉ có CSS. Một số đã tác phẩm nghệ thuật tinh tế, và một số đã phức tạp. Mục yêu thích của tôi là những thứ liên quan đến các đối tượng 3D, ví dụ: quả bóng nảy và điều này khối đóng gói.

Lúc đầu, tôi không biết chúng được tạo ra như thế nào. Sau này tôi đọc và học được rất nhiều điều từ hướng dẫn hay này của Ana Tudor.

Hóa ra, việc xây dựng và tạo hoạt ảnh cho các đối tượng 3D bằng CSS không khác nhiều so với việc làm với Máy xay sinh tố, chỉ với một chút hương vị khác nhau.

Kết luận

Trong bài viết này, chúng tôi đã kiểm tra hành vi của hoạt ảnh CSS khi một animate-* tài sản bị thay đổi. Đặc biệt là chúng tôi đã tìm ra các giải pháp để “phát lại hoạt ảnh” và “chuyển động chậm hoạt ảnh”.

Tôi hy vọng bạn thấy bài viết này thú vị. Xin vui lòng cho tôi biết suy nghĩ của bạn!

Dấu thời gian:

Thêm từ Thủ thuật CSS