Explore CSS Transitions, the mathematics of timing functions (Cubic-bezier curves), and how to optimize animation performance using compositor-only rendering properties.
This lesson is currently only available in Vietnamese. Please switch the language toggle in the menu to Vietnamese to read the full guide and take the interactive quiz.
Trong thiết kế giao diện hiện đại (UI/UX), sự chuyển tiếp mượt mà giữa các trạng thái (như khi rê chuột vào nút bấm, mở rộng menu, ẩn hiện modal) chính là yếu tố phân biệt một sản phẩm chuyên nghiệp với một giao diện chắp vá thô cứng.
CSS cung cấp thuộc tính transition để giải quyết bài toán này một cách cực kỳ đơn giản.
Tuy nhiên, đằng sau sự đơn giản đó là một loạt các khái niệm toán học về đường cong gia tốc (Easing
Curves) và các cơ chế tối ưu hóa render phần cứng (GPU Compositing) mà mọi kỹ sư frontend cần phải làm
chủ để đạt hiệu năng mượt mà 60fps.
1. Thuộc tính CSS Transition & Cách hoạt động
Cơ chế hoạt động của Transition dựa trên việc lắng nghe sự thay đổi của các thuộc tính CSS (thường
được kích hoạt bởi pseudo-class như :hover, :focus, hoặc qua việc JavaScript
gán class mới) và tự động tính toán bù suy hao (interpolate) để thay đổi giá trị đó tăng/giảm dần theo
thời gian thay vì nhảy số lập tức.
Một khai báo đầy đủ bao gồm 4 thuộc tính cấu thành:
-
transition-property: Chỉ định tên thuộc tính muốn tạo hiệu ứng chuyển tiếp (ví dụ:
background-color,transform). -
transition-duration: Thời gian diễn ra hiệu ứng chuyển tiếp, nhận đơn vị giây
(
s) hoặc mili-giây (ms). - transition-timing-function: Quy định đường cong gia tốc (tốc độ chuyển động nhanh hay chậm theo thời gian).
- transition-delay: Khoảng thời gian chờ đợi trước khi bắt đầu thực hiện hiệu ứng chuyển tiếp.
transition: all 0.3s. Điều này cực kỳ có hại
cho hiệu năng. Trình duyệt sẽ buộc phải theo dõi sự thay đổi của tất cả mọi thuộc
tính CSS của phần tử đó. Nếu có các thuộc tính kích hoạt Reflow (như margin,
padding), trang web sẽ lập tức bị giật lag nghiêm trọng, đặc biệt trên thiết bị di động
cấu hình yếu. Hãy luôn chỉ định chính xác thuộc tính cần chuyển tiếp (như
transition: transform 0.3s, opacity 0.3s).
2. Bản chất toán học của Easing Curves: Cubic Bezier
Đường cong gia tốc (Easing Curve) định nghĩa cách giá trị CSS thay đổi dọc theo dòng thời gian của hiệu ứng. Nó được mô tả toán học bằng một đường cong Bézier bậc 3 (Cubic Bézier).
Đường cong Cubic Bézier được định nghĩa bởi 4 điểm kiểm soát: $P_0, P_1, P_2, P_3$. Trong đó, $P_0 (0,0)$ là thời điểm bắt đầu và $P_3 (1,1)$ là thời điểm kết thúc. Chúng cố định. Hai điểm còn lại, $P_1 (x_1, y_1)$ và $P_2 (x_2, y_2)$, là các điểm neo điều hướng lực kéo giúp bạn tự do tùy biến đường cong.
Hàm toán học mô tả đường cong Bézier bậc 3 theo tham số $t \in [0, 1]$:
\[B(t) = (1-t)^3 P_0 + 3(1-t)^2 t P_1 + 3(1-t) t^2 P_2 + t^3 P_3\]
Trong CSS, chúng ta khai báo đường cong này qua cú pháp: cubic-bezier(x1, y1, x2, y2).
-
linear: Vận tốc không đổi suốt quá trình. Tương đươngcubic-bezier(0, 0, 1, 1). -
ease: Bắt đầu chậm, tăng tốc nhanh ở giữa và giảm tốc chậm ở cuối. Tương đươngcubic-bezier(0.25, 0.1, 0.25, 1). -
ease-in: Bắt đầu chậm và tăng tốc dần đến cuối. Tương đươngcubic-bezier(0.42, 0, 1, 1). -
ease-out: Bắt đầu nhanh và giảm tốc chậm dần về cuối. Tương đươngcubic-bezier(0, 0, 0.58, 1). -
ease-in-out: Bắt đầu chậm, tăng tốc ở giữa và giảm tốc dần ở cuối. Tương đươngcubic-bezier(0.42, 0, 0.58, 1).
3. Hiệu năng dựng hình: CPU Reflow vs GPU Compositing
Khi viết transition, lựa chọn thuộc tính nào để thay đổi sẽ quyết định trực tiếp hiệu năng mượt mà của giao diện. Trình duyệt dựng hình (rendering pipeline) trải qua 3 giai đoạn chính ảnh hưởng bởi CSS:
- Layout (Reflow): Tính toán lại hình học, kích thước và vị trí của các khối. Tác vụ này cực kỳ tốn CPU vì thay đổi một phần tử có thể kéo theo tính toán lại toàn bộ trang (Layout Tree Rebuild).
- Paint (Repaint): Tô màu pixel, vẽ chữ, viền, đổ bóng của các hộp. Tốn tài nguyên vì phải vẽ lại giao diện.
- Composite (Dàn dựng): Gửi các lớp ảnh (Layers) đã vẽ lên GPU để sắp lớp và hiển thị. Cực kỳ nhanh vì GPU được thiết kế cho việc dịch chuyển, biến đổi hình học phẳng siêu tốc.
left hoặc top, trình duyệt bắt buộc phải chạy lại cả 3
giai đoạn Layout -> Paint -> Composite ở mỗi khung hình (frame). Điều này làm CPU
quá tải và gây ra hiện tượng giật lag.Ngược lại, khi sử dụng
transform: translateX(), trình duyệt sẽ đưa phần tử đó lên một
lớp đồ họa riêng (Graphics Layer). Khi dịch chuyển, trình duyệt bỏ qua hoàn toàn bước Layout và
Paint, GPU chỉ việc thao tác di chuyển lớp ảnh đó ở giai đoạn Composite Only. Tốc
độ render đạt tối đa 60fps hoặc 120fps.
Sân chơi tương tác: Easing & Performance Lab
Dưới đây là công cụ so sánh trực quan hiệu năng dựng hình. Bạn có thể thay đổi thời gian, đường cong gia tốc để quan sát đường cong Bézier được vẽ trên Canvas, đồng thời nhấn "Chạy thử hiệu ứng" để xem sự khác biệt giữa hai kỹ thuật dịch chuyển:
Thiết lập cấu hình
left (Layout-heavy)
CPU Reflow -> Paint
transform (Compositor)
Composite Only (GPU)
<div class="container">
<!-- Cách 1: Kém hiệu năng do gây Reflow liên tục -->
<div class="box box-left">Left</div>
<!-- Cách 2: Tối ưu, mượt mà nhờ chạy trên GPU -->
<div class="box box-transform">GPU</div>
</div>
4. Kỹ thuật nâng cao: Bouncing Effect & Hardware Acceleration
Bằng cách đẩy điểm tọa độ dọc của $P_1$ hoặc $P_2$ ra ngoài khoảng giới hạn $[0, 1]$ (ví dụ: gán $y_1$ hoặc $y_2$ lớn hơn 1 hoặc nhỏ hơn 0), bạn có thể tạo nên các hiệu ứng nảy (Bouncing/Elastic) cực kỳ sống động mà không cần tới JavaScript hay Keyframe phức tạp.
.button-pop {
transition: transform 0.4s cubic-bezier(0.68, -0.6, 0.32, 1.6);
}
.button-pop:hover {
transform: scale(1.15); /* Phần tử sẽ hơi co rúm lại trước khi phình to nảy ra ngoài */
}
Để ép buộc trình duyệt gán một phần tử vào một Graphics Layer riêng ngay từ đầu nhằm tăng tốc phần
cứng, bạn có thể sử dụng thuộc tính will-change:
.gpu-accelerated-layer {
will-change: transform, opacity; /* Báo trước cho GPU chuẩn bị tài nguyên */
}
Trắc nghiệm ôn tập
Câu 1: Thuộc tính nào sau đây khi thay đổi trạng thái sẽ có hiệu năng cao nhất (chỉ kích hoạt Composite Only)?
Trắc nghiệm ôn tập
Câu 2: Trong hàm cubic-bezier(x1, y1, x2, y2), giá trị nào sau đây bị giới hạn bắt buộc từ 0 đến 1?