CSS Transition – Kiểm soát quy trình chuyển động của hiệu ứng
Ở phần trước, hẳn các bạn đã biết cách tạo hiệu ứng chuyển động cho các phần tử. Nhưng transition không chỉ đơn giản là dừng lại ở đó. Bởi vì ngoài các phần có hiệu ứng ra thì nó còn có thêm một câu hỏi khác nữa. Đó là quá trình chuyển động đó sẽ diễn ra như thế nào? Kiểm soát quy trình chuyển ...
Ở phần trước, hẳn các bạn đã biết cách tạo hiệu ứng chuyển động cho các phần tử. Nhưng transition không chỉ đơn giản là dừng lại ở đó. Bởi vì ngoài các phần có hiệu ứng ra thì nó còn có thêm một câu hỏi khác nữa. Đó là quá trình chuyển động đó sẽ diễn ra như thế nào?
Kiểm soát quy trình chuyển động với Timing Function
Thuộc tính transition-timing-function
Thuật ngữ này có thể còn hơi mơ hồ nhưng kiểm soát quy trình chuyển động ở đây không phải là chúng ta sẽ quy định cách chúng chuyển động như thế nào. Kiểu xoay 360 độ rồi chạy lòng vòng chẳng hạn. Cái này được gọi là cách thức chuyển động. Còn chúng ta sẽ dựa trên những thuộc tính mà W3C cung cấp sẵn để tạo cho chúng chuyển động theo những quy trình khác nhau dựa trên các mốc thời gian khác nhau.
W3C cung cấp cho chúng ta một thuộc tính có tên gọi là transition-timing-function. Với các giá trị được gọi là timing function. Ta tạm gọi chúng là các hàm hiệu chỉnh thời gian. Chúng gồm 5 giá trị chính là: ease, ease-in, ease-out, ease-in-out và linear.
Cách sử dụng
Cách dùng chúng cũng đơn giản như tên của chúng vậy. Tôi sẽ lấy ví dụ để các bạn dễ hình dung luôn. Ta sẽ sử dung transition để làm một cái hộp hình vuông màu xanh. Nó sẽ thay đổi chiều rộng từ 100px sang 300px khi ta rê chuột vào.
.box { awidth: 100px; height: 100px; background-color: #3498db; color: #fff; } .box:hover { awidth: 300px; transition-property: awidth; transition-duration: 1s; transition-timing-function: ease; //Cách sử dụng }
Ở đây bạn đã thấy thuộc tính transition-timing-function được sử dụng như thế nào rồi đấy. Thế nhưng có một thắc mắc là 5 giá trị trên nó khác nhau như thế nào? Dưới đây là ví dụ cho cả 5 giá trị kia. Các bạn hãy click vào demo để thấy kết quả:
Bảng mô tả chuyển động
Nếu các bạn để ý kỹ một chút xíu, các hộp màu xanh này sẽ chuyển động khác nhau theo như bảng mô tả dưới đây:
Giá trị | Mô tả |
---|---|
ease | Hiệu ứng của quá trình chuyển đổi với sự bắt đầu chậm. Sau đó nhanh chóng, rồi kết thúc chậm. |
ease-in | Hiệu ứng của quá trình chuyển đổi với sự bắt đầu chậm. |
ease-out | Hiệu ứng của quá trình chuyển đổi với kết thúc chậm. |
ease-in-out | Hiệu ứng của quá trình chuyển đổi với sự bắt đầu và kết thúc chậm. |
linear | Hiệu ứng của quá trình chuyển đổi với cùng một tốc độ từ đầu đến cuối. Tương đương với khi không sử dụng thuộc tính `transition-timing-function`. |
Và đó cũng là lý do vì sao tôi gọi đây là thuộc tính kiểm soát quy trình chuyển động. Chúng chuyển động theo từng quy trình khác nhau như nhanh dần rồi chậm, chậm dần rồi nhanh,… Thật sự rất khác biệt với chuyển động bình thường như linear đúng không các bạn?
Cách khai báo rút gọn
Và cũng như thuộc tính transition-duration, transition-timing-function cũng cho phép chúng ta truyền vào nhiều giá trị tương ứng với từng transition-property mà chúng ta đã khai báo. Chúng sẽ ngăn cách nhau bởi dấu phẩy như thế này:
.box:hover { transition-property: border-radius, background-color; transition-duration: 2s, 1s; transition-timing-function: ease, ease-in; }
Giờ thì với các timing-function này, các bạn đã thấy hiệu ứng của mình trong mượt mà và ảo diệu như thế nào rồi đó. Nhưng nếu các bạn không muốn nó mượt mà ảo diệu mà lại muốn xem nó di chuyển từng khung hình frame by frame thì có được hay không?
Sử dụng Timing Function với Step
Ví dụ
Câu trả lời là hoàn toàn được nhé các bạn. Đó là khi bạn sử dụng timing-function với giá trị là step. Nó có cú pháp như sau:
.example-1 { transition-timing-function: steps(1, start); } .example-2 { transition-timing-function: steps(1, end); }
Như các bạn thấy, step chỉ có hai tham số được ngăn cách nhau bởi dấu phẩy. Tham số đầu tiên là một số nguyên, còn tham số thứ hai là start hoặc end. Điều này có ý nghĩa gì?
Hãy xem demo này để thấy rõ các bạn nhé. Nhớ rê chuột vào ô vuông màu xanh:
Ở trên là ví dụ với steps(4,start) và steps(4,end) trong khoảng thời gian 1s (duration = 1s). Thoạt nhìn vào demo, các bạn sẽ không thấy có sự khác biệt gì. Tuy nhiên hãy bắt tay đào sâu hơn ta sẽ thấy sự khác biệt.
Ý nghĩa của từng giá trị
Đầu tiên là tham số thứ nhất, con số 4 này có ý nghĩa gì? Nó chính là số bước nhảy (bước chuyển động) của phần tử này trong khoảng thời gian các giá trị chuyển động là 1s. Nghĩa là trong 1s phần tử này thực hiện 4 bước chuyển động. Tương đương mỗi bước chuyển động sẽ thực hiện trong 0.25s. Các bạn hãy thử quay lại phần demo và đếm lại xem có phải chuyển động đó có 4 bước không nhé.
Còn tham số thứ hai, nó đơn giản là chỉ định chuyển động sẽ được bắt đầu vào khoảng thời gian nào trên mỗi bước nhảy. Tương ứng với start là thực hiện chuyển động trong khoảng thời gian khi bắt đầu mỗi bước nhảy. Ngược lại end là thực hiện chuyển động trong khoảng thời gian ở cuối mỗi bước nhảy. Tôi sẽ đặt lại demo với step là 1 cũng trong thời gian 1s để các bạn thấy rõ hơn:
Cách viết rút gọn
Dĩ nhiên là số bước nhảy càng lớn thì chuyển động sẽ càng mượt mà. Và cũng như họ hàng của nó, nó cũng chấp nhận cho chúng ta truyền vào nhiều giá trị ương ứng với từng transition-property mà chúng ta đã khai báo. Chúng sẽ ngăn cách nhau bởi dấu phẩy như thế này:
.end { transition-property: background, border; transition-duration: 1s, 1s; transition-timing-function: steps(5,start), steps(2,end); }
Các bạn có thể xem qua demo sau đây để thấy được sự kỳ cục khi chúng ta sử dụng steps để hành nghề:
Bây giờ các bạn chắc hẳn đã không còn “bối rối” với từ kiểm soát quy trình chuyển động hay hàm hiệu chỉnh thời gian nữa rồi phải không? Các bạn có thể thực hành áp dụng ngay vào trong dự án của mình. Tuy nhiên, transition-timing-function còn cho phép chúng ta kiểm soát quy trình này một cách tuyệt vời hơn nữa!
Kiểm soát quy trình chuyển động nâng cao
Đường cong Bezier
Nghe từ nâng cao thấy có vẻ “nguy hiểm” quá phải không? Tuy nhiên các bạn đừng ngần ngại vì chẳng có nguy hiểm gì cả đâu. Ngược lại còn “sướng” hơn nữa là đằng khác.
Trong ví dụ trên, các bạn đã làm quen với các transition-timing-function với các giá trị nhằm kiểm soát quy trình chuyển động theo kiểu “hoạt hình” nhất có thể. Tuy nhiên, một điều mà có lẽ các bạn không biết đó là các chuyển động này nó được dựa trên Bezier Curve. Tạm gọi là đường cong Bezier.
Đường cong Bezier là một mô hình đường cong thường được sử dụng trong đồ họa máy tính. Nếu bạn đã làm việc với các chương trình đồ họa vector như AI (Adobe Illustrator) hay CorelDRAW, bạn sẽ dễ dàng bắt gặp mô hình này. Đường cong này được hình thành với bốn điểm như minh họa trên.
Đường cong Bézier cũng được sử dụng trong các lĩnh vực đồ họa. Cụ thể là kiểm soát quy trình chuyển động của vật thể theo thời gian. Ví dụ, một đường cong Bézier có thể được sử dụng để xác định vận tốc theo thời gian của một đối tượng như một biểu tượng di chuyển từ A đến B. Chứ không phải chỉ đơn giản là di chuyển với bước nhảy cố định (step). Ví dụ như sự chuyển động của mũi tên màu đỏ trên.
Tìm hiểu giá trị cubic-bezier trong Transition
Và thật may mắn khi Bezier Curve cũng được ứng dụng trong Transition với giá trị cubic-bezier, nó là một giá trị hết sức đặc biệt của bộ giá trị các hàm kiểm soát thời gian (timing-function) vì nó cho phép ta tự động tùy chỉnh các kiểu chuyển động với các mốc thời gian khác nhau. Cú pháp nó sẽ như sau:
transition-timing-function: cubic-bezier(P1x, P1y, P2x, P2y);
Có 4 điểm nhưng trong cú pháp trển chỉ đề cập tới P1 và P2 tương ứng với X (trục tung) và giá trị Y (trục hoành).
Vì như các bạn thấy trong hình vẽ P0(0,0) còn P3(1,1) nên hai điểm này đã là cố định nên không được nhắc tới. Và cũng vì lý do đó, các điểm P1x, P1y, P2x, P2y phải là các giá trị nằm giữa 0 và 1. Ý nghĩa của nó là biểu diễn từ 0 đến 100% thời gian tương ứng với từ 0 đến 100% chuyển động của hiệu ứng (mối tương quan giữa transition-duration và transition-timing-function).
Lưu ý
Theo một số tài liệu, nếu các bạn sử dụng các giá trị ví dụ như là cubic-bezier(2,3,5,2), đường chuyển động sẽ nằm ngoài trục tuyến tính, và điều tệ nhất là nó sẽ không hoạt động trên một số trình duyệt. Và đề xuất sử dụng cubic-bezier với giá trị khác 0 và 1 đã được chấp thuận trên WebKit Bugzilla (khung ứng dụng mã nguồn mở xây dựng trình duyệt web của App Inc) nên các bạn cứ thoải mái sử dụng các giá trị tùy biến bất kỳ.
Nhưng sử dụng cubic-bezier như thế nào cho đúng?
Đây là một câu hỏi cực kỳ “hack não” vì cubic-bezier cực kỳ trừu tượng nhưng có một điều tuyệt vời là bạn có thể sử dụng công cụ cubic-bezier.com của Lea Verou để tự tay, tận mắt xem quy trình chuyển động của cubic-bezier và quyết định chuyển động như thế nào sẽ phù hợp với mình.
Tuy nhiên, ở khía cạnh kỹ thuật, tôi sẽ mổ xẻ các giá trị trong hàm cubic-bezier này. Theo như các tài liệu, x tức trục tung là thời gian chuyển động còn y tức trục hoành sẽ là sự chuyển động thay đổi theo thời gian x của phần tử (lưu ý là nó không chuyển động theo đường cong mà là một đường thẳng dựa trên cubic-bezier giống như hình ảnh có mũi tên chuyển động màu đỏ ở phía trên). Các bạn nên vào website cubic-bezier.com để tự mình trải nghiệm vì các giá trị này nếu chỉ diễn giải suông như thế này thì nó rất là mơ hồ.
Minh họa các giá trị bằng cubic-bezier
Và nếu chúng ta chuyển 5 giá trị ease, ease-in, ease-out, ease-in-out và linear sang cubic-bezier thì lần lượt chúng sẽ có giá trị như sau:
ease: cubic-bezier(0.25,0.1,0.25,1)
ease-in: cubic-bezier(0.42, 0.0, 1.0, 1.0)
ease-out: cubic-bezier(0.0, 0.0, 0.58, 1.0)
ease-in-out: cubic-bezier(0.42, 0.0, 0.58, 1.0)
linear: cubic-bezier(0,0,1,1)
Ở đây, sau khi sử dụng cubic-bezier, tôi có làm một demo tên lửa khởi động, các bạn có thể tham khảo để thấy sự thú vị của Transition:
Kết luận
Qua tutorial rất dài dòng này, các bạn lại có thêm cái nhìn mới cũng như kiến thức mới về Transition, các bạn sẽ có thể tự tay sáng tạo và tùy chỉnh các hiệu ứng mang dấu ấn của riêng mình. Và lại tiếp tục áp dụng nó vào các đồ án của chính mình. Thích quá phải không?