Explore all courses in this category.
Explore all courses in this category.
Nguyễn Đình Cường
0 comment
09 Nov, 2026
Một chút chuyển động đúng chỗ khiến giao diện sống động và dễ hiểu hơn: nút đổi màu khi rê chuột, menu trượt ra, thông báo mờ dần. Bạn không cần thư viện nặng nề, CSS đã có sẵn hai công cụ cho việc này là transition và animation.
Transition làm cho sự thay đổi của một thuộc tính diễn ra từ từ thay vì tức thì. Bạn khai báo ở trạng thái gốc:
.button {
background: #2563eb;
transform: translateY(0);
transition: background 0.2s ease, transform 0.2s ease;
}
.button:hover {
background: #1d4ed8;
transform: translateY(-2px);
}Cú pháp gồm tên thuộc tính, thời lượng, hàm tốc độ và có thể thêm độ trễ. Hàm tốc độ phổ biến là ease, ease-in-out, linear. Hãy khai báo transition ở trạng thái gốc, không phải ở :hover, để hiệu ứng chạy cả lúc vào và lúc ra.
Đừng dùng transition: all bừa bãi. Nó có thể làm chuyển động những thuộc tính bạn không định, và gây tốn tài nguyên. Hãy liệt kê rõ các thuộc tính cần chuyển.
Khi cần chuyển động phức tạp hơn hoặc tự chạy mà không cần sự kiện, dùng @keyframes:
@keyframes fade-in-up {
from {
opacity: 0;
transform: translateY(16px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.toast {
animation: fade-in-up 0.4s ease-out both;
}Bạn định nghĩa các mốc (từ from đến to, hoặc theo phần trăm như 0%, 50%, 100%) rồi gắn vào phần tử qua thuộc tính animation. Một số thuộc tính con đáng biết:
animation-duration: thời lượng một vòng.animation-iteration-count: số lần lặp, hoặc infinite để lặp mãi.animation-delay: độ trễ trước khi chạy.animation-fill-mode: both giữ trạng thái đầu trước khi chạy và trạng thái cuối sau khi chạy.animation-direction: chiều chạy, ví dụ alternate để chạy xuôi rồi ngược.@keyframes spin {
to { transform: rotate(360deg); }
}
.spinner {
width: 32px;
height: 32px;
border: 4px solid #cbd5e1;
border-top-color: #2563eb;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}Chỉ với vài dòng, bạn có một biểu tượng đang tải, không cần ảnh hay thư viện.
Không phải thuộc tính nào cũng rẻ như nhau. Khi bạn thay đổi width, height, margin hay top, trình duyệt thường phải tính lại bố cục của cả trang, việc này tốn kém và dễ gây giật. Hai thuộc tính transform và opacity thường được trình duyệt xử lý hiệu quả hơn nhiều, có thể giao cho GPU. Vì vậy:
transform: translate() thay vì đổi left hoặc top.transform: scale().opacity.Một số người bị chóng mặt hoặc khó chịu khi gặp hiệu ứng chuyển động mạnh, và họ có thể bật tùy chọn "giảm chuyển động" trong hệ điều hành. Bạn có thể tôn trọng điều này bằng media query:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}Đây là một trong số ít trường hợp !important được chấp nhận vì mục đích khả năng tiếp cận.
Một hiệu ứng rất thường gặp trên giao diện danh sách khóa học hay sản phẩm là thẻ nhấc lên nhẹ và đổ bóng đậm hơn:
.card {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover,
.card:focus-within {
transform: translateY(-4px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.18);
}Hãy để ý :focus-within: nó áp dụng hiệu ứng khi một phần tử bên trong thẻ nhận focus bàn phím, giúp người dùng không dùng chuột cũng nhận được phản hồi tương tự. Đây là một thói quen nhỏ nhưng tạo khác biệt cho khả năng tiếp cận. Đừng quên rằng màn hình cảm ứng không có hover thực sự, nên hiệu ứng không bao giờ nên là cách duy nhất để truyền đạt thông tin quan trọng.
Transition dành cho thay đổi giữa hai trạng thái, animation dành cho chuỗi chuyển động phức tạp hoặc tự chạy. Ưu tiên transform và opacity, tôn trọng prefers-reduced-motion, và đừng lạm dụng.
Nếu bạn thích làm giao diện sinh động và muốn học có lộ trình rõ ràng, hãy xem các khóa học trên codebem.com để chọn khóa phù hợp.
Nguyễn Đình Cường
0 comment