Hãy hình dung thế này: bạn tham gia một dự án mới, đi sâu vào cơ sở mã và trong vài giờ đầu tiên, bạn phát hiện ra điều gì đó quen thuộc đến khó chịu. Rải rác khắp các bảng định kiểu, bạn sẽ tìm thấy nhiều định nghĩa @keyframes cho các hoạt ảnh cơ bản giống nhau. Ba hiệu ứng mờ dần khác nhau, hai hoặc ba biến thể trang trình bày, một số hoạt ảnh thu phóng và ít nhất hai hoạt ảnh quay khác nhau, vì tại sao không? @keyframes xung { từ { tỷ lệ: 1; } đến { tỷ lệ: 1,1; } }

@keyframes xung lớn hơn { 0%, 20%, 100% { tỷ lệ: 1; } 10%, 40% { tỷ lệ: 1,2; } }

Nếu kịch bản này nghe có vẻ quen thuộc thì bạn không đơn độc. Theo kinh nghiệm của tôi qua nhiều dự án khác nhau, một trong những chiến thắng nhanh chóng nhất quán mà tôi có thể mang lại là hợp nhất và tiêu chuẩn hóa các khung hình chính. Nó đã trở thành một mẫu đáng tin cậy đến mức giờ đây tôi mong đợi việc dọn dẹp này là một trong những nhiệm vụ đầu tiên của tôi trên bất kỳ cơ sở mã mới nào. Logic đằng sau sự hỗn loạn Sự dư thừa này hoàn toàn hợp lý khi bạn nghĩ về nó. Tất cả chúng ta đều sử dụng các hoạt ảnh cơ bản giống nhau trong công việc hàng ngày của mình: mờ dần, trượt, thu phóng, quay và các hiệu ứng phổ biến khác. Những hoạt ảnh này khá đơn giản và thật dễ dàng để đưa ra định nghĩa @keyframes nhanh chóng để hoàn thành công việc. Nếu không có hệ thống hoạt ảnh tập trung, các nhà phát triển sẽ viết các khung hình chính này một cách tự nhiên từ đầu mà không biết rằng các hoạt ảnh tương tự đã tồn tại ở nơi khác trong cơ sở mã. Điều này đặc biệt phổ biến khi làm việc trong các kiến ​​trúc dựa trên thành phần (điều mà hầu hết chúng ta ngày nay đều làm), vì các nhóm thường làm việc song song trên các phần khác nhau của ứng dụng. Kết quả? Hoạt hình hỗn loạn. Vấn đề nhỏ Các vấn đề rõ ràng nhất với việc sao chép khung hình chính là lãng phí thời gian phát triển và phình to mã không cần thiết. Nhiều định nghĩa khung hình chính có nghĩa là có nhiều nơi để cập nhật khi yêu cầu thay đổi. Cần điều chỉnh thời gian của hoạt ảnh mờ dần? Bạn sẽ cần phải tìm kiếm mọi phiên bản trên cơ sở mã của mình. Bạn muốn chuẩn hóa các chức năng nới lỏng? Chúc may mắn tìm thấy tất cả các biến thể. Việc nhân lên nhiều điểm bảo trì này khiến ngay cả việc cập nhật hoạt ảnh đơn giản cũng trở thành một công việc tốn thời gian. Vấn đề lớn hơn Việc sao chép khung hình chính này tạo ra một vấn đề nguy hiểm hơn nhiều: bẫy phạm vi toàn cầu. Ngay cả khi làm việc với các kiến ​​trúc dựa trên thành phần, các khung hình chính CSS luôn được xác định trong phạm vi toàn cục. Điều này có nghĩa là tất cả các khung hình chính đều áp dụng cho tất cả các thành phần. Luôn luôn. Có, hoạt ảnh của bạn không nhất thiết phải sử dụng khung hình chính mà bạn đã xác định trong thành phần của mình. Nó sử dụng các khung hình chính cuối cùng khớp với cùng tên đã được tải vào phạm vi toàn cầu. Miễn là tất cả các khung hình chính của bạn giống hệt nhau thì đây có thể chỉ là một vấn đề nhỏ. Nhưng thời điểm bạn muốn tùy chỉnh hoạt ảnh cho một trường hợp sử dụng cụ thể, bạn sẽ gặp rắc rối hoặc tệ hơn, bạn sẽ là người gây ra chúng. Hoạt ảnh của bạn sẽ không hoạt động vì thành phần khác được tải sau thành phần của bạn, ghi đè khung hình chính của bạn hoặc thành phần của bạn tải lần cuối và vô tình thay đổi hành vi hoạt ảnh cho mọi thành phần khác bằng cách sử dụng tên của khung hình chính đó và bạn thậm chí có thể không nhận ra điều đó. Đây là một ví dụ đơn giản chứng minh vấn đề: .thành phần-một { /*kiểu dáng thành phần */ hình ảnh động: xung 1s dễ dàng vào ra vô hạn thay thế; }

/* định nghĩa @keyframes này sẽ không hoạt động */ @keyframes xung { từ { tỷ lệ: 1; } đến { tỷ lệ: 1,1; } }

/* ở phần sau của mã... */

.thành phần-hai { /*kiểu dáng thành phần */ hoạt hình: xung 1s dễ dàng ra vào vô hạn; }

/* keyframe này sẽ áp dụng cho cả hai thành phần */ @keyframes xung { 0%, 20%, 100% { tỷ lệ: 1; } 10%, 40% { tỷ lệ: 1,2; } }

Cả hai thành phần đều sử dụng cùng một tên hoạt ảnh, nhưng định nghĩa @keyframes thứ hai sẽ ghi đè lên tên hoạt ảnh đầu tiên. Bây giờ cả thành phần một và thành phần hai sẽ sử dụng khung hình chính thứ hai, bất kể thành phần nào đã xác định khung hình chính nào. Xem Mã thông báo khung hình bút - Bản demo 1 [phân tách] của Amit Sheen. Phần tồi tệ nhất? Điều này thường hoạt động hoàn hảo trong quá trình phát triển cục bộ nhưng lại xảy ra sự cố một cách bí ẩn trong quá trình sản xuất khi quá trình xây dựng thay đổi thứ tự tải biểu định kiểu của bạn. Bạn kết thúc bằng các hoạt ảnh hoạt động khác nhau tùy thuộc vào thành phần nào được tải và theo trình tự nào. Giải pháp: Khung hình chính thống nhất Câu trả lời cho sự hỗn loạn này đơn giản đến mức đáng ngạc nhiên: các khung hình chính động được xác định trước được lưu trữ trong biểu định kiểu được chia sẻ. Thay vì để mọi thành phần tự xác định hoạt ảnh của riêng mình, chúng tôi tạo các khung hình chính tập trung được ghi chép đầy đủ, dễ dàng sử dụng.sử dụng, có thể bảo trì và điều chỉnh theo nhu cầu cụ thể của dự án của bạn. Hãy coi nó như mã thông báo khung hình chính. Giống như chúng ta sử dụng mã thông báo cho màu sắc và khoảng cách và nhiều người trong chúng ta đã sử dụng mã thông báo cho các thuộc tính hoạt ảnh, như thời lượng và chức năng tăng tốc, tại sao không sử dụng mã thông báo cho khung hình chính? Cách tiếp cận này có thể tích hợp một cách tự nhiên với mọi quy trình làm việc về mã thông báo thiết kế hiện tại mà bạn đang sử dụng, đồng thời giải quyết cả vấn đề nhỏ (sao chép mã) và vấn đề lớn hơn (xung đột phạm vi toàn cầu) cùng một lúc. Ý tưởng rất đơn giản: tạo ra một nguồn thông tin chính xác duy nhất cho tất cả các hoạt ảnh thông thường của chúng ta. Biểu định kiểu được chia sẻ này chứa các khung hình chính được chế tạo cẩn thận bao gồm các mẫu hoạt ảnh mà dự án của chúng tôi thực sự sử dụng. Không còn phải đoán xem hoạt ảnh mờ dần đã tồn tại ở đâu đó trong cơ sở mã của chúng tôi hay chưa. Không còn vô tình ghi đè lên hình ảnh động từ các thành phần khác. Nhưng mấu chốt ở đây là: đây không chỉ là những hoạt ảnh sao chép-dán tĩnh. Chúng được thiết kế linh hoạt và có thể tùy chỉnh thông qua các thuộc tính tùy chỉnh CSS, cho phép chúng tôi duy trì tính nhất quán trong khi vẫn linh hoạt điều chỉnh hoạt ảnh cho phù hợp với các trường hợp sử dụng cụ thể, chẳng hạn như nếu bạn cần hoạt ảnh “xung” lớn hơn một chút ở một nơi. Xây dựng mã thông báo khung hình chính đầu tiên Một trong những thành quả dễ dàng đầu tiên mà chúng ta nên giải quyết là hoạt ảnh “làm mờ dần”. Trong một trong những dự án gần đây của tôi, tôi đã tìm thấy hơn một chục định nghĩa làm mờ dần riêng biệt và vâng, tất cả chúng chỉ đơn giản là tạo hoạt ảnh cho độ mờ từ 0 đến 1. Vì vậy, hãy tạo một biểu định kiểu mới, gọi nó là kf-tokens.css, nhập nó vào dự án của chúng ta và đặt các khung hình chính của chúng ta với các nhận xét thích hợp bên trong nó. /* keyframes-tokens.css */

/* * Fade In - hoạt hình lối vào mờ dần * Cách sử dụng: hoạt hình: kf-fade-in 0,3 giây dễ dàng; */ @keyframes kf-fade-in { từ { độ mờ: 0; } đến { độ mờ: 1; } }

Tuyên bố @keyframes duy nhất này thay thế tất cả các hoạt ảnh mờ dần rải rác đó trên cơ sở mã của chúng tôi. Sạch sẽ, đơn giản và có thể áp dụng trên toàn cầu. Và bây giờ chúng ta đã xác định được mã thông báo này, chúng ta có thể sử dụng nó từ bất kỳ thành phần nào trong suốt dự án của mình: .modal { hoạt ảnh: kf-fade-in 0,3 giây dễ dàng thoát ra; }

.chú giải công cụ { hoạt ảnh: kf-fade-in 0,2 giây dễ dàng ra vào; }

.thông báo { hoạt ảnh: kf-fade-in 0,5 giây dễ dàng thoát ra; }

Xem Mã thông báo khung hình bút - Bản trình diễn 2 [rẽ nhánh] của Amit Sheen. Lưu ý: Chúng tôi đang sử dụng tiền tố kf- trong tất cả các tên @keyframes của mình. Tiền tố này đóng vai trò như một không gian tên giúp ngăn xung đột việc đặt tên với các hoạt ảnh hiện có trong dự án và làm rõ ngay rằng các khung hình chính này đến từ tệp mã thông báo khung hình chính của chúng tôi. Tạo một slide động Các khung hình chính kf-fade-in hoạt động rất tốt vì nó đơn giản và có rất ít chỗ để làm mọi thứ rối tung lên. Tuy nhiên, trong các hoạt ảnh khác, chúng ta cần năng động hơn nhiều và ở đây chúng ta có thể tận dụng sức mạnh to lớn của các thuộc tính tùy chỉnh CSS. Đây là nơi mã thông báo khung hình chính thực sự tỏa sáng so với hoạt ảnh tĩnh rải rác. Hãy lấy một tình huống phổ biến: hoạt ảnh “trượt vào”. Nhưng trượt vào từ đâu? 100px từ bên phải? 50% từ bên trái? Có nên nhập từ trên cùng của màn hình? Hoặc có thể trôi vào từ phía dưới? Rất nhiều khả năng, nhưng thay vì tạo các khung hình chính riêng biệt cho từng hướng và từng biến thể, chúng ta có thể tạo một mã thông báo linh hoạt thích ứng với mọi tình huống: /* * Slide In - hoạt hình trượt định hướng * Sử dụng --kf-slide-from để điều khiển hướng * Mặc định: trượt từ trái sang (-100%) * Cách sử dụng: * hoạt ảnh: kf-slide-in 0,3 giây dễ dàng thoát ra; * --kf-slide-from: -100px 0; // trượt từ trái * --kf-slide-from: 100px 0; // trượt từ bên phải * --kf-slide-from: 0 -50px; // trượt từ trên xuống */

@keyframes kf-slide-in { từ { dịch: var(--kf-slide-from, -100% 0); } đến { dịch: 0 0; } }

Bây giờ chúng ta có thể sử dụng mã thông báo @keyframes duy nhất này cho bất kỳ hướng trượt nào chỉ bằng cách thay đổi thuộc tính tùy chỉnh --kf-slide-from: .sidebar { hoạt ảnh: kf-slide-in 0,3 giây dễ dàng thoát ra; /* Sử dụng giá trị mặc định: trượt từ trái */ }

.thông báo { hoạt ảnh: kf-slide-in 0,4 giây dễ dàng thoát ra; --kf-slide-from: 0 -50px; /*trượt từ trên xuống*/ }

.modal { hoạt hình: kf-mờ dần trong 0,5 giây, kf-slide-in 0,5s khối bezier(0,34, 1,56, 0,64, 1); --kf-slide-từ: 50px 50px; /*trượt từ dưới lên bên phải */ }

Cách tiếp cận này mang lại cho chúng tôi sự linh hoạt đáng kinh ngạc trong khi vẫn duy trì tính nhất quán. Một khai báo khung hình chính, khả năng vô hạn. Xem Mã thông báo khung hình bút - Bản trình diễn 3 [rẽ nhánh] của Amit Sheen. Và nếu chúng ta muốn làm cho hoạt ảnh của mình trở nên linh hoạt hơn nữa, cho phép tạo ra các hiệu ứng "trượt ra", chúng ta có thểchỉ cần thêm thuộc tính tùy chỉnh --kf-slide-to, tương tự như những gì chúng ta sẽ thấy trong phần tiếp theo. Khung hình chính thu phóng hai chiều Một hoạt ảnh phổ biến khác được sao chép trong các dự án là hiệu ứng “thu phóng”. Cho dù đó là một sự phóng to tinh tế cho các tin nhắn chúc mừng, phóng to đáng kể cho các phương thức hay hiệu ứng thu nhỏ nhẹ nhàng cho các tiêu đề, hoạt ảnh thu phóng đều có ở khắp mọi nơi. Thay vì tạo các khung hình chính riêng biệt cho từng giá trị tỷ lệ, hãy xây dựng một bộ khung hình chính kf-zoom linh hoạt:

/* * Thu phóng - thu nhỏ hình ảnh động * Sử dụng --kf-zoom-from và --kf-zoom-to để kiểm soát giá trị tỷ lệ * Mặc định: thu phóng từ 80% đến 100% (0,8 đến 1) * Cách sử dụng: * hoạt hình: dễ dàng thu phóng kf-zoom 0,2 giây; * --kf-zoom-từ: 0,5; --kf-phóng to: 1; // thu phóng từ 50% đến 100% * --kf-zoom-từ: 1; --kf-phóng to: 0; // thu phóng từ 100% đến 0% * --kf-zoom-từ: 1; --kf-phóng to: 1.1; // thu phóng từ 100% đến 110% */

@keyframes kf-zoom { từ { tỷ lệ: var(--kf-zoom-from, 0,8); } đến { tỷ lệ: var(--kf-zoom-to, 1); } }

Với một định nghĩa, chúng ta có thể đạt được bất kỳ biến thể thu phóng nào mà chúng ta cần: .bánh mì nướng { hoạt hình: kf-trượt vào 0,2 giây, kf-zoom 0,4 giây dễ dàng; --kf-slide-từ: 0 100%; /*trượt từ trên xuống*/ /* Sử dụng mức thu phóng mặc định: tỷ lệ từ 80% đến 100% */ }

.modal { hoạt ảnh: kf-zoom 0,3s khối bezier(0,34, 1,56, 0,64, 1); --kf-thu phóng-từ: 0; /* Thu phóng ấn tượng từ 0% đến 100% */ }

.tiêu đề { hoạt hình: kf-fade-in 2s, kf-zoom 2s dễ dàng sử dụng; --kf-thu phóng-từ: 1,2; --kf-phóng to: 0,8; /*giảm tỉ lệ nhẹ nhàng*/ }

Giá trị mặc định là 0,8 (80%) hoạt động hoàn hảo cho hầu hết các thành phần giao diện người dùng, như tin nhắn và thiệp chúc mừng, trong khi vẫn dễ dàng tùy chỉnh cho các trường hợp đặc biệt. Xem Mã thông báo khung hình bút - Bản trình diễn 4 [rẽ nhánh] của Amit Sheen. Bạn có thể nhận thấy điều gì đó thú vị trong các ví dụ gần đây: chúng tôi đã kết hợp hoạt ảnh. Một trong những lợi thế chính khi làm việc với mã thông báo @keyframes là chúng được thiết kế để tích hợp liền mạch với nhau. Thành phần mượt mà này là có chủ ý chứ không phải ngẫu nhiên. Chúng ta sẽ thảo luận chi tiết hơn về bố cục hoạt ảnh sau, bao gồm cả chỗ chúng có thể trở thành vấn đề, nhưng hầu hết các kết hợp đều đơn giản và dễ thực hiện. Lưu ý: Khi viết bài này, và có lẽ vì viết nó nên tôi thấy mình đang suy nghĩ lại toàn bộ ý tưởng về hoạt ảnh lối vào. Với tất cả những tiến bộ gần đây về CSS, liệu chúng ta có còn cần chúng nữa không? May mắn thay, Adam Argyle đã khám phá những câu hỏi tương tự và thể hiện chúng một cách xuất sắc trên blog của mình. Điều này không mâu thuẫn với những gì được viết ở đây, nhưng nó đưa ra một cách tiếp cận đáng xem xét, đặc biệt nếu dự án của bạn phụ thuộc nhiều vào hoạt ảnh lối vào. Hoạt ảnh liên tục Trong khi các hoạt ảnh truy cập, như “làm mờ”, “trượt” và “thu phóng” xảy ra một lần rồi dừng lại, thì các hoạt ảnh liên tục lặp lại vô thời hạn để thu hút sự chú ý hoặc biểu thị hoạt động đang diễn ra. Hai hoạt ảnh liên tục phổ biến nhất mà tôi gặp là “quay” (để chỉ báo tải) và “xung” (để làm nổi bật các yếu tố quan trọng). Những hoạt ảnh này đưa ra những thách thức đặc biệt khi tạo mã thông báo khung hình chính. Không giống như hoạt ảnh lối vào thường chuyển từ trạng thái này sang trạng thái khác, hoạt ảnh liên tục cần có khả năng tùy chỉnh cao trong kiểu hành vi của chúng. Bác sĩ quay Mọi dự án dường như đều sử dụng nhiều hoạt ảnh quay. Một số quay theo chiều kim đồng hồ, số khác quay ngược chiều kim đồng hồ. Một số thực hiện một vòng xoay 360 độ, số khác thực hiện nhiều lượt để có hiệu ứng nhanh hơn. Thay vì tạo các khung hình chính riêng biệt cho từng biến thể, hãy tạo một vòng quay linh hoạt có thể xử lý tất cả các tình huống:

/* * Spin - hoạt hình xoay * Sử dụng --kf-spin-from và --kf-spin-to để kiểm soát phạm vi xoay * Sử dụng --kf-spin-turns để kiểm soát lượng xoay * Mặc định: quay từ 0deg đến 360deg (1 vòng quay đầy đủ) * Cách sử dụng: * hoạt hình: kf-spin 1s tuyến tính vô hạn; * --kf-spin-turn: 2; // 2 vòng quay đầy đủ * --kf-spin-từ: 0deg; --kf-spin-to: 180deg; // nửa vòng quay * --kf-spin-từ: 0deg; --kf-spin-to: -360deg; // ngược chiều kim đồng hồ */

@keyframes kf-spin { từ { xoay: var(--kf-spin-from, 0deg); } đến { xoay: calc(var(--kf-spin-from, 0deg) + var(--kf-spin-to, 360deg) * var(--kf-spin-turns, 1)); } }

Bây giờ chúng ta có thể tạo bất kỳ biến thể spin nào mà chúng ta thích:

.loading-spinner { hoạt hình: kf-spin 1s tuyến tính vô hạn; /* Sử dụng mặc định: xoay từ 0deg đến 360deg */ }

.tải nhanh { hình ảnh động: kf-spin 1.2s thay thế vô hạn dễ dàng vào ra; --kf-spin-lượt: 3; /* 3 vòng quay đầy đủ cho mỗi hướng trong mỗi chu kỳ*/ }

.steped-đảo ngược { hoạt ảnh: kf-spin 1,5 giây bước (8) vô hạn; --kf-spin-to: -360deg; /*ngược chiều kim đồng hồ*/ }

.tinh tế-ngọ nguậy { hình ảnh động: kf-spin 2s thay thế vô hạn dễ dàng vào ra; --kf-spin-từ: -16deg; --kf-spin-to: 32deg; /* lắc lư 36 độ: trong khoảng từ -18 độ đến +18 độ */ }

Xem Mã thông báo khung hình bút - Bản trình diễn 5 [rẽ nhánh] của Amit Sheen. Cái hay của phương pháp này là các khung hình chính giống nhau hoạt động để tải vòng quay, biểu tượng xoay, hiệu ứng lắc lư và thậm chí cả hoạt ảnh nhiều lượt phức tạp. Nghịch lý xung Hoạt ảnh xung phức tạp hơn vì chúng có thể “xung” các thuộc tính khác nhau. Một số xung theo thang đo, một số khác đo độ mờ và một số thuộc tính màu xung như độ sáng hoặc độ bão hòa. Thay vì tạo các khung hình chính riêng biệt cho từng thuộc tính, chúng ta có thể tạo các khung hình chính hoạt động với bất kỳ thuộc tính CSS nào. Dưới đây là ví dụ về khung hình chính xung với các tùy chọn tỷ lệ và độ mờ:

/* * Xung - hoạt hình xung * Sử dụng --kf-pulse-scale-from và --kf-pulse-scale-to để kiểm soát phạm vi tỷ lệ * Sử dụng --kf-pulse-opacity-from và --kf-pulse-opacity-to để kiểm soát phạm vi độ mờ * Mặc định: không có xung (tất cả giá trị 1) * Cách sử dụng: * hoạt hình: kf-pulse 2s thay thế vô hạn dễ dàng vào ra; * --kf-xung-thang-từ: 0,95; --kf-xung-thang-to: 1,05; // xung tỷ lệ * --kf-xung-độ mờ-từ: 0,7; --kf-xung-độ mờ-đến: 1; // xung độ mờ */

@keyframes kf-xung { từ { thang đo: var(--kf-pulse-scale-from, 1); độ mờ: var(--kf-pulse-opacity-from, 1); } đến { thang đo: var(--kf-pulse-scale-to, 1); độ mờ: var(--kf-pulse-opacity-to, 1); } }

Điều này tạo ra một xung linh hoạt có thể tạo hiệu ứng động cho nhiều thuộc tính: .kêu gọi hành động { hình ảnh động: kf-xung 0,6 giây thay thế vô hạn; --kf-xung-độ mờ-từ: 0,5; /* xung độ mờ */ }

.notification-dot { hình ảnh động: kf-xung 0,6 giây thay thế vô hạn dễ dàng ra vào; --kf-xung-thang-từ: 0,9; --kf-pulse-scale-to: 1.1; /* xung tỷ lệ */ }

.text-đánh dấu { hình ảnh động: kf-xung 1,5 giây dễ dàng vô hạn; --kf-xung-thang-từ: 0,8; --kf-xung-độ mờ-từ: 0,2; /* tỷ lệ và xung độ mờ */ }

Xem Mã thông báo khung hình bút - Bản trình diễn 6 [rẽ nhánh] của Amit Sheen. Khung hình chính kf-pulse đơn này có thể xử lý mọi thứ, từ việc thu hút sự chú ý một cách tinh tế đến những điểm nổi bật ấn tượng, đồng thời dễ dàng tùy chỉnh. Nới lỏng nâng cao Một trong những điều tuyệt vời khi sử dụng mã thông báo khung hình chính là việc mở rộng thư viện hoạt ảnh của chúng tôi dễ dàng như thế nào và cung cấp các hiệu ứng mà hầu hết các nhà phát triển sẽ không buồn viết từ đầu, chẳng hạn như đàn hồi hoặc nảy. Dưới đây là ví dụ về mã thông báo khung hình chính “nảy” đơn giản sử dụng thuộc tính tùy chỉnh --kf-bounce-from để kiểm soát độ cao bước nhảy. /* * Bounce - hoạt hình lối vào nảy * Sử dụng --kf-bounce-from để kiểm soát độ cao bước nhảy * Mặc định: nhảy từ 100vh (tắt màn hình) * Cách sử dụng: * hoạt ảnh: kf-bounce 3s dễ dàng; * --kf-bounce-từ: 200px; // nhảy từ độ cao 200px */

@keyframes kf-bounce { 0% { dịch: 0 calc(var(--kf-bounce-from, 100vh) * -1); }

34% { dịch: 0 calc(var(--kf-bounce-from, 100vh) * -0.4); }

55% { dịch: 0 calc(var(--kf-bounce-from, 100vh) * -0.2); }

72% { dịch: 0 calc(var(--kf-bounce-from, 100vh) * -0.1); }

85% { dịch: 0 calc(var(--kf-bounce-from, 100vh) * -0.05); }

94% { dịch: 0 calc(var(--kf-bounce-from, 100vh) * -0.025); }

99% { dịch: 0 calc(var(--kf-bounce-from, 100vh) * -0.0125); }

22%, 45%, 64%, 79%, 90%, 97%, 100% { dịch: 0 0; chức năng hoạt hình-thời gian: dễ dàng; } }

Các hoạt ảnh như “co giãn” phức tạp hơn một chút do các phép tính bên trong khung hình chính. Chúng ta cần xác định --kf-elastic-from-X và --kf-elastic-from-Y riêng biệt (cả hai đều là tùy chọn) và chúng cùng nhau cho phép chúng ta tạo một lối vào linh hoạt từ bất kỳ điểm nào trên màn hình.

/* * Elastic In - hoạt hình lối vào đàn hồi * Sử dụng --kf-elastic-from-X và --kf-elastic-from-Y để kiểm soát vị trí bắt đầu * Mặc định: nhập từ giữa trên cùng (0, -100vh) * Cách sử dụng: * hoạt hình: kf-elastic-in 2s dễ dàng ra vào cả hai; * --kf-elastic-from-X: -50px; * --kf-elastic-from-Y: -200px; // nhập từ (-50px, -200px) */

@keyframes kf-elastic-in { 0% { dịch: calc(var(--kf-elastic-from-X, -50vw) * 1) calc(var(--kf-elastic-from-Y, 0px) * 1); }

16% { dịch: calc(var(--kf-elastic-from-X, -50vw) * -0.3227) calc(var(--kf-elastic-from-Y, 0px) * -0.3227); }

28% { dịch: calc(var(--kf-elastic-from-X, -50vw) * 0.1312)calc(var(--kf-elastic-from-Y, 0px) * 0.1312); }

44% { dịch: calc(var(--kf-elastic-from-X, -50vw) * -0.0463) calc(var(--kf-elastic-from-Y, 0px) * -0.0463); }

59% { dịch: calc(var(--kf-elastic-from-X, -50vw) * 0,0164) calc(var(--kf-elastic-from-Y, 0px) * 0,0164); }

73% { dịch: calc(var(--kf-elastic-from-X, -50vw) * -0.0058) calc(var(--kf-elastic-from-Y, 0px) * -0.0058); }

88% { dịch: calc(var(--kf-elastic-from-X, -50vw) * 0,0020) calc(var(--kf-elastic-from-Y, 0px) * 0,0020); }

100% { dịch: 0 0; } }

Cách tiếp cận này giúp dễ dàng sử dụng lại và tùy chỉnh các khung hình chính nâng cao trong dự án của chúng tôi, chỉ bằng cách thay đổi một thuộc tính tùy chỉnh duy nhất.

.bounce-and-zoom { hoạt hình: kf-bounce 3s dễ dàng, kf-zoom 3s tuyến tính; --kf-thu phóng-từ: 0; }

.bounce-và-trượt { thành phần hoạt hình: thêm; /* Cả hai hoạt ảnh đều sử dụng tính năng dịch */ hoạt hình: kf-bounce 3s dễ dàng, kf-slide-in 3s dễ dàng ra ngoài; --kf-slide-từ: -200px; }

.elastic-in { hoạt hình: kf-elastic-in 2s dễ dàng ra vào cả hai; }

Xem Mã thông báo khung hình bút - Bản trình diễn 7 [rẽ nhánh] của Amit Sheen. Cho đến thời điểm này, chúng tôi đã thấy cách có thể hợp nhất các khung hình chính một cách thông minh và hiệu quả. Tất nhiên, bạn có thể muốn điều chỉnh mọi thứ để phù hợp hơn với nhu cầu dự án của mình, nhưng chúng tôi đã đưa ra các ví dụ về một số hoạt ảnh phổ biến và các trường hợp sử dụng hàng ngày. Và với các mã thông báo khung hình chính này, giờ đây chúng tôi có các khối xây dựng mạnh mẽ để tạo hoạt ảnh nhất quán, có thể duy trì trong toàn bộ dự án. Không còn khung hình chính trùng lặp, không còn xung đột phạm vi toàn cầu. Chỉ là một cách gọn gàng, thuận tiện để đáp ứng mọi nhu cầu hoạt hình của chúng ta. Nhưng câu hỏi thực sự là: Làm thế nào để chúng ta kết hợp những khối xây dựng này lại với nhau? Đặt tất cả lại với nhau Chúng tôi đã thấy rằng việc kết hợp các mã thông báo khung hình chính cơ bản rất đơn giản. Chúng ta không cần bất cứ điều gì đặc biệt ngoài việc xác định hoạt ảnh đầu tiên, xác định hoạt ảnh thứ hai, đặt các biến nếu cần, thế là xong. /* Làm mờ dần + trượt vào */ .bánh mì nướng { hoạt hình: kf-mờ dần trong 0,4 giây, kf-slide-in 0,4s khối bezier(0,34, 1,56, 0,64, 1); --kf-slide-from: 0 40px; }

/* Phóng to + làm mờ */ .modal { hoạt hình: kf-mờ dần trong 0,3 giây, kf-zoom 0,3s khối bezier(0,34, 1,56, 0,64, 1); --kf-thu phóng-từ: 0,7; --kf-phóng to: 1; }

/* Trượt vào + xung */ .thông báo { hoạt hình: kf-trượt vào 0,5 giây, kf-xung 1,2s thay thế vô hạn dễ dàng vào ra; --kf-slide-from: -100px 0; --kf-xung-thang-từ: 0,95; --kf-xung-thang-to: 1,05; }

Những sự kết hợp này hoạt động rất tốt vì mỗi hoạt ảnh nhắm đến một thuộc tính khác nhau: độ mờ, biến đổi (dịch/tỷ lệ), v.v. Nhưng đôi khi có xung đột và chúng ta cần biết lý do cũng như cách giải quyết chúng. Khi hai hoạt ảnh cố gắng tạo hoạt ảnh cùng một thuộc tính — ví dụ: cả tỷ lệ hoạt ảnh hoặc cả độ mờ hoạt ảnh — kết quả sẽ không như bạn mong đợi. Theo mặc định, chỉ một trong các hoạt ảnh thực sự được áp dụng cho thuộc tính đó, đây là hoạt ảnh cuối cùng trong danh sách hoạt ảnh. Đây là hạn chế về cách CSS xử lý nhiều hoạt ảnh trên cùng một thuộc tính. Ví dụ: điều này sẽ không hoạt động như dự định vì chỉ áp dụng hoạt ảnh kf-pulse. .bad-combo { hoạt hình: kf-zoom 0,5 giây về phía trước, kf-xung 1,2s luân phiên vô hạn; --kf-thu phóng-từ: 0,5; --kf-phóng to: 1,2; --kf-xung-thang-từ: 0,8; --kf-pulse-scale-to: 1.1; }

Bổ sung hoạt hình Cách đơn giản và trực tiếp nhất để xử lý nhiều hoạt ảnh ảnh hưởng đến cùng một thuộc tính là sử dụng thuộc tính animation-composition. Trong ví dụ cuối cùng ở trên, hoạt ảnh kf-pulse thay thế hoạt ảnh kf-zoom, vì vậy chúng ta sẽ không thấy mức thu phóng ban đầu và sẽ không đạt được tỷ lệ mong đợi là 1,2. Bằng cách thiết lập thành phần hoạt ảnh cần thêm, chúng tôi yêu cầu trình duyệt kết hợp cả hai hoạt ảnh. Điều này mang lại cho chúng tôi kết quả mà chúng tôi mong muốn. .thành phần-hai { thành phần hoạt hình: thêm; }

Xem Mã thông báo khung hình bút - Bản trình diễn 8 [rẽ nhánh] của Amit Sheen. Cách tiếp cận này hoạt động tốt trong hầu hết các trường hợp chúng tôi muốn kết hợp các hiệu ứng trên cùng một thuộc tính. Nó cũng hữu ích khi chúng ta cần kết hợp hình ảnh động với các giá trị thuộc tính tĩnh. Ví dụ: nếu chúng ta có một phần tử sử dụng thuộc tính dịch để định vị nó chính xác ở nơi chúng ta muốn và sau đó chúng ta muốn tạo hoạt ảnh cho nó bằng các khung hình chính kf-slide-in, chúng ta sẽ có một bước nhảy khó chịu mà không cần bố cục hoạt ảnh. Xem Mã thông báo khung hình bút - Bản trình diễn 9 [rẽ nhánh] của Amit Sheen. Với bộ thành phần hoạt ảnh được thêm vào, hoạt ảnh được kết hợp mượt mà với thành phần hiện cóbiến đổi, để phần tử giữ nguyên vị trí và hoạt hình như mong đợi. Hoạt hình loạng choạng Một cách khác để xử lý nhiều hoạt ảnh là “ngồi xen kẽ” chúng - nghĩa là bắt đầu hoạt ảnh thứ hai một chút sau khi hoạt ảnh đầu tiên kết thúc. Nó không phải là giải pháp phù hợp cho mọi trường hợp, nhưng nó rất hữu ích khi chúng ta có hoạt ảnh lối vào theo sau là hoạt ảnh liên tục. /* mờ dần + xung độ mờ */ .thông báo { hoạt hình: kf-fade-in 2s dễ dàng, kf-xung 0,5s 2s dễ dàng vào ra thay thế vô hạn; --kf-xung-độ mờ-đến: 0,5; }

Xem Mã thông báo khung hình bút - Bản demo 10 [phân tách] của Amit Sheen. Vấn đề đặt hàng Phần lớn hoạt ảnh mà chúng tôi làm việc sử dụng thuộc tính biến đổi. Trong hầu hết các trường hợp, điều này đơn giản là thuận tiện hơn. Nó cũng có lợi thế về hiệu suất vì hoạt ảnh chuyển đổi có thể được tăng tốc GPU. Nhưng nếu chúng ta sử dụng các phép biến đổi, chúng ta cần chấp nhận rằng thứ tự chúng ta thực hiện các phép biến đổi là quan trọng. Nhiều. Trong các khung hình chính của chúng tôi cho đến nay, chúng tôi đã sử dụng các biến đổi riêng lẻ. Theo thông số kỹ thuật, những điều này luôn được áp dụng theo thứ tự cố định: đầu tiên, phần tử được dịch, sau đó xoay, sau đó chia tỷ lệ. Điều này có ý nghĩa và là điều mà hầu hết chúng ta mong đợi. Tuy nhiên, nếu chúng ta sử dụng thuộc tính biến đổi, thứ tự viết các hàm sẽ là thứ tự chúng được áp dụng. Trong trường hợp này, nếu chúng ta di chuyển thứ gì đó 100 pixel trên trục X và sau đó xoay nó 45 độ thì điều đó không giống như lần đầu tiên xoay nó 45 độ và sau đó di chuyển nó 100 pixel. /* Hình vuông màu hồng: Dịch trước, sau đó xoay */ .example-one { biến đổi: dịchX (100px) xoay (45deg); }

/* Hình vuông màu xanh lá cây: Xoay trước, sau đó dịch */ .example-hai { biến đổi: xoay (45deg) dịchX (100px); }

Xem Mã thông báo khung hình bút - Bản demo 11 [phân tách] của Amit Sheen. Nhưng theo thứ tự biến đổi, tất cả các biến đổi riêng lẻ — mọi thứ chúng tôi đã sử dụng cho mã thông báo khung hình chính — đều diễn ra trước các hàm biến đổi. Điều đó có nghĩa là mọi thứ bạn đặt trong thuộc tính biến đổi sẽ xảy ra sau hoạt ảnh. Nhưng nếu bạn đặt, chẳng hạn như dịch cùng với các khung hình chính kf-spin, thì quá trình dịch sẽ diễn ra trước hoạt ảnh. Bạn bối rối chưa?! Điều này dẫn đến tình huống trong đó các giá trị tĩnh có thể gây ra các kết quả khác nhau cho cùng một hoạt ảnh, như trong trường hợp sau:

/* Hoạt ảnh chung cho cả hai vòng quay */ .spinner { hoạt hình: kf-spin 1s tuyến tính vô hạn; }

/* Vòng quay màu hồng: dịch trước khi xoay (biến đổi riêng lẻ) */ .spinner-hồng { dịch: 100% 50%; }

/* Vòng quay màu xanh lá cây: xoay rồi dịch (thứ tự hàm) */ .spinner-xanh { biến đổi: dịch (100%, 50%); }

Xem Mã thông báo khung hình bút - Bản trình diễn 12 [phân nhánh] của Amit Sheen. Bạn có thể thấy rằng vòng quay đầu tiên (màu hồng) nhận được một bản dịch xảy ra trước khi vòng quay kf-spin, do đó, đầu tiên nó di chuyển đến vị trí của nó và sau đó quay. Công cụ quay tròn thứ hai (màu xanh lá cây) nhận được hàm dịch() xảy ra sau khi biến đổi riêng lẻ, do đó, phần tử đầu tiên sẽ quay, sau đó di chuyển so với góc hiện tại của nó và chúng ta có được hiệu ứng quỹ đạo rộng đó. Không, đây không phải là một lỗi. Đó chỉ là một trong những điều chúng ta cần biết về CSS và ghi nhớ khi làm việc với nhiều hoạt ảnh hoặc nhiều biến đổi. Nếu cần, bạn cũng có thể tạo một bộ khung hình chính kf-spin-alt bổ sung để xoay các phần tử bằng hàm xoay(). Giảm chuyển động Và khi chúng ta đang nói về các khung hình chính thay thế, chúng ta không thể bỏ qua tùy chọn “không có hoạt ảnh”. Một trong những lợi thế lớn nhất của việc sử dụng mã thông báo khung hình chính là khả năng truy cập có thể được tích hợp và thực sự khá dễ thực hiện. Bằng cách thiết kế các khung hình chính có lưu ý đến khả năng truy cập, chúng tôi có thể đảm bảo rằng những người dùng thích giảm chuyển động sẽ có được trải nghiệm mượt mà hơn, ít gây mất tập trung hơn mà không phải làm thêm việc hoặc sao chép mã. Ý nghĩa chính xác của “Giảm chuyển động” có thể thay đổi một chút từ hoạt ảnh này sang hoạt ảnh khác và từ dự án này sang dự án khác, nhưng dưới đây là một số điểm quan trọng cần lưu ý: Tắt tiếng khung hình chính Mặc dù một số hoạt ảnh có thể được làm mềm hoặc chậm lại, nhưng có những hoạt ảnh khác sẽ biến mất hoàn toàn khi yêu cầu giảm chuyển động. Hoạt ảnh xung là một ví dụ điển hình. Để đảm bảo những hoạt ảnh này không chạy ở chế độ giảm chuyển động, chúng ta chỉ cần gói chúng trong truy vấn phương tiện thích hợp.

@media (thích-giảm-chuyển động: không ưu tiên) { @keyfrmaes kf-xung { từ { thang đo: var(--kf-pulse-scale-from, 1); độ mờ: var(--kf-pulse-opacity-from, 1); } đến { thang đo: var(--kf-pulse-scale-to, 1); độ mờ:var(--kf-pulse-opacity-to, 1); } } }

Điều này đảm bảo rằng những người dùng đã đặt tùy chọn giảm chuyển động thành giảm sẽ không nhìn thấy hoạt ảnh và sẽ có được trải nghiệm phù hợp với tùy chọn của họ. Ngay lập tức Có một số khung hình chính mà chúng tôi không thể xóa một cách đơn giản, chẳng hạn như hoạt ảnh lối vào. Giá trị phải thay đổi, phải hoạt hình; nếu không, phần tử sẽ không có giá trị chính xác. Nhưng trong chuyển động giảm, quá trình chuyển đổi này từ giá trị ban đầu sẽ diễn ra ngay lập tức. Để đạt được điều này, chúng tôi sẽ xác định một bộ khung hình chính bổ sung trong đó giá trị sẽ chuyển ngay sang trạng thái kết thúc. Chúng trở thành khung hình chính mặc định của chúng tôi. Sau đó, chúng tôi sẽ thêm các khung hình chính thông thường bên trong truy vấn phương tiện để đặt ưu tiên-giảm-chuyển động thành không ưu tiên, giống như trong ví dụ trước. /* bật ngay lập tức để giảm chuyển động */ @keyframes kf-zoom { từ, đến { tỷ lệ: var(--kf-zoom-to, 1); } }

@media (thích-giảm-chuyển động: không ưu tiên) { /* Khung hình chính thu phóng gốc */ @keyframes kf-zoom { từ { tỷ lệ: var(--kf-zoom-from, 0,8); } đến { tỷ lệ: var(--kf-zoom-to, 1); } } }

Bằng cách này, những người dùng thích giảm chuyển động sẽ thấy phần tử xuất hiện ngay lập tức ở trạng thái cuối cùng, trong khi những người khác sẽ nhận được chuyển đổi hoạt hình. Cách tiếp cận mềm mại Có những trường hợp chúng tôi muốn giữ lại một số chuyển động nhưng nhẹ nhàng và êm dịu hơn nhiều so với hoạt ảnh gốc. Ví dụ: chúng ta có thể thay thế lối vào bị trả lại bằng hiệu ứng mờ dần nhẹ nhàng.

@keyframes kf-bounce { /* Làm mờ dần để giảm chuyển động */ }

@media (thích-giảm-chuyển động: không ưu tiên) { @keyframes kf-bounce { /* Khung hình chính bị trả lại ban đầu */ } }

Giờ đây, người dùng đã bật tính năng giảm chuyển động vẫn có được cảm giác về ngoại hình nhưng không có chuyển động mạnh như hoạt ảnh nảy hoặc đàn hồi. Với các khối xây dựng sẵn có, câu hỏi tiếp theo là làm thế nào để biến chúng thành một phần của quy trình làm việc thực tế. Viết các khung hình chính linh hoạt là một chuyện, nhưng để làm cho chúng trở nên đáng tin cậy trong một dự án lớn đòi hỏi một số chiến lược mà tôi đã phải học hỏi một cách khó khăn. Chiến lược triển khai & phương pháp thực hành tốt nhất Khi chúng tôi có một thư viện vững chắc về mã thông báo khung hình chính, thách thức thực sự là làm cách nào để đưa chúng vào công việc hàng ngày.

Sự cám dỗ là bỏ tất cả các khung hình chính vào cùng một lúc và tuyên bố vấn đề đã được giải quyết, nhưng trên thực tế, tôi nhận thấy rằng kết quả tốt nhất đến từ việc áp dụng dần dần. Bắt đầu với các hoạt ảnh phổ biến nhất, chẳng hạn như mờ dần hoặc trượt. Đây là những chiến thắng dễ dàng thể hiện giá trị ngay lập tức mà không cần phải viết lại nhiều. Đặt tên là một điểm khác đáng được chú ý. Tiền tố hoặc không gian tên nhất quán giúp xác định rõ hoạt ảnh nào là mã thông báo và hoạt ảnh nào là hoạt ảnh cục bộ. Nó cũng ngăn chặn những va chạm vô tình và giúp các thành viên mới trong nhóm nhận ra hệ thống dùng chung trong nháy mắt. Tài liệu cũng quan trọng như chính mã. Ngay cả một nhận xét ngắn phía trên mỗi mã thông báo khung hình chính cũng có thể tiết kiệm hàng giờ suy đoán sau này. Nhà phát triển có thể mở tệp mã thông báo, quét tìm hiệu ứng họ cần và sao chép thẳng kiểu sử dụng vào thành phần của họ. Tính linh hoạt là điều làm cho phương pháp này đáng nỗ lực. Bằng cách hiển thị các thuộc tính tùy chỉnh hợp lý, chúng tôi cung cấp cho các nhóm không gian để điều chỉnh hoạt ảnh mà không làm hỏng hệ thống. Đồng thời, cố gắng không quá phức tạp. Cung cấp các nút bấm quan trọng và giữ cho phần còn lại có ý kiến. Cuối cùng, hãy nhớ khả năng tiếp cận. Không phải mọi hoạt hình đều cần giải pháp thay thế giảm chuyển động, nhưng nhiều hoạt hình thì có. Việc thực hiện sớm những điều chỉnh này có nghĩa là chúng tôi không bao giờ phải trang bị thêm chúng sau này và điều đó cho thấy mức độ quan tâm mà người dùng của chúng tôi sẽ nhận thấy ngay cả khi họ không bao giờ đề cập đến điều đó.

Theo kinh nghiệm của tôi, việc coi mã thông báo khung hình chính như một phần trong quy trình làm việc của mã thông báo thiết kế của chúng tôi là điều khiến chúng gắn bó. Một khi đã vào đúng vị trí, chúng sẽ không còn cảm giác giống như những hiệu ứng đặc biệt nữa mà trở thành một phần của ngôn ngữ thiết kế, một phần mở rộng tự nhiên về cách sản phẩm chuyển động và phản hồi. Kết thúc Hoạt ảnh có thể là một trong những phần thú vị nhất khi xây dựng giao diện, nhưng nếu không có cấu trúc, chúng cũng có thể trở thành một trong những nguồn gây thất vọng lớn nhất. Bằng cách coi các khung hình chính là mã thông báo, bạn biến thứ gì đó thường lộn xộn và khó quản lý thành một hệ thống rõ ràng, có thể dự đoán được. Giá trị thực không chỉ ở việc lưu một vài dòng mã. Bạn có thể tự tin rằng khi bạn sử dụng hiệu ứng làm mờ, trượt, thu phóng hoặc xoay, bạn sẽ biết chính xác nó sẽ hoạt động như thế nào trong toàn bộ dự án. Đó là sự linh hoạt đến từ các thuộc tính tùy chỉnh mà không có sự hỗn loạn của các biến thể vô tận. Và nó nằm ở khả năng tiếp cận được tích hợp sẵn trong nền tảng chứ không phải được thêm vào nhưmột suy nghĩ lại. Tôi đã thấy những ý tưởng này hoạt động ở các nhóm khác nhau và các cơ sở mã khác nhau và mô hình luôn giống nhau. Sau khi có mã thông báo, các khung hình chính sẽ không còn là một tập hợp các thủ thuật rải rác và trở thành một phần của ngôn ngữ thiết kế. Chúng làm cho sản phẩm có chủ ý hơn, nhất quán hơn và sống động hơn. Nếu bạn rút ra được một điều từ bài viết này, hãy coi như thế này: hoạt ảnh xứng đáng được quan tâm và cấu trúc như chúng ta đã dành cho màu sắc, kiểu chữ và khoảng cách. Một khoản đầu tư nhỏ vào mã thông báo khung hình chính sẽ mang lại lợi ích mỗi khi giao diện của bạn di chuyển.

You May Also Like

Enjoyed This Article?

Get weekly tips on growing your audience and monetizing your content — straight to your inbox.

No spam. Join 138,000+ creators. Unsubscribe anytime.

Create Your Free Bio Page

Join 138,000+ creators on Seemless.

Get Started Free