Menu

Transition CSS: thuộc tính, thời gian, easing và độ trễ

Transition trong CSS tạo chuyển động cho một thuộc tính từ giá trị cũ sang giá trị mới khi nó thay đổi, ví dụ lúc hover. Tìm hiểu cách viết gọn transition, so sánh mọi timing function, những gì có và không thể transition, mẹo cho height: auto và chế độ giảm chuyển động.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Transition qua một ví dụ

Transition bảo trình duyệt: khi thuộc tính này thay đổi, hãy chuyển dần trong khoảng thời gian này thay vì đổi ngay lập tức. Đặt nó trong quy tắc bình thường của phần tử, không chỉ trong :hover:

Hover vào nút đầu tiên: màu của nó chuyển dần sang xanh lá và nút nhích lên 4px trong 0,4 giây, còn khi bạn rời con trỏ đi, cùng transition đó chạy ngược lại. Nút thứ hai có transition: none nên đổi ngay tức thì. Người dùng bàn phím cũng thấy hiệu ứng tương tự qua :focus-visible.

Cách viết gọn transition

transition: background-color 0.3s ease-in-out 0.1s;
/*          property         duration timing    delay */
Thuộc tính đầy đủĐặt giá trị gìMặc định
transition-propertynhững thuộc tính nào chuyển động (all, hoặc một danh sách)all
transition-durationkéo dài bao lâu, tính bằng s hoặc ms0s
transition-timing-functionđường cong tốc độease
transition-delaychờ bao lâu trước khi bắt đầu (có thể âm)0s

Thời lượng mặc định là 0s, nên không có gì chuyển động cho tới khi bạn đặt giá trị cho nó. Trong cách viết gọn, giá trị thời gian đầu tiên luôn là thời lượng và giá trị thứ hai là độ trễ. Muốn mỗi thuộc tính có cấu hình riêng, hãy ngăn cách chúng bằng dấu phẩy:

.card {
  transition: transform 0.2s ease-out, box-shadow 0.4s ease-out;
}

So sánh các timing function

Timing function quyết định tốc độ thay đổi ra sao trong suốt transition. Nhấn Play và cả bảy thanh sẽ đi cùng một quãng đường trong cùng 1,5 giây:

Timing functionCảm giác
lineartốc độ đều, kiểu máy móc
ease (mặc định)khởi đầu nhanh, dừng nhẹ nhàng
ease-inkhởi đầu chậm, kết thúc nhanh: hợp với thứ đang rời đi
ease-outkhởi đầu nhanh, kết thúc chậm: hợp với thứ đang xuất hiện
ease-in-outchậm ở cả hai đầu
cubic-bezier(x1, y1, x2, y2)đường cong của riêng bạn; y lớn hơn 1 sẽ vượt quá rồi lùi về
steps(n)nhảy thành n bước bằng nhau, không có khung hình ở giữa

Với hiệu ứng hover và menu, ease-out với thời lượng từ 150ms đến 300ms tạo cảm giác phản hồi nhanh.

Những gì có thể transition

Những thuộc tính có giá trị trung gian đều transition được: màu sắc, độ dài (width, padding, margin), opacity, transform, box-shadow, border-radius, filter, background-color. Những thuộc tính nhảy giữa các từ khóa, như display hay font-family, sẽ đổi ngay lập tức.

height: auto là trường hợp hay gặp nhất: một panel mở từ height: 0 tới height: auto mặc định không có chuyển động, vì trình duyệt không tính các giá trị nằm giữa 0 và "auto". Một cách xử lý đáng tin cậy là dùng lớp bọc dạng grid với một hàng duy nhất đi từ 0fr tới 1fr:

aria-expanded cho người dùng trình đọc màn hình biết panel đang mở hay đóng, điều mà riêng chuyển động không làm được.

Chạy code khi transition kết thúc

Sự kiện transitionend được kích hoạt khi một transition kết thúc, mỗi thuộc tính một lần. Dùng nó để làm gì đó sau chuyển động, chẳng hạn chuyển focus hoặc xóa một phần tử:

Tôn trọng chế độ giảm chuyển động

Một số người bật "giảm chuyển động" trong cài đặt hệ thống vì chuyển động trên màn hình khiến họ chóng mặt hoặc mất tập trung. Hãy giữ các hiệu ứng mờ dần về màu và độ trong suốt, và bỏ các chuyển động lớn, bằng một media query:

@media (prefers-reduced-motion: reduce) {
  .btn { transition: background-color 0.2s ease; } /* no movement, only the color */
}

Giữ transition mượt mà

transform và opacity là những thuộc tính tạo chuyển động nhẹ nhất: trình duyệt có thể di chuyển và làm mờ phần tử mà không phải tính lại bố cục. Transition cho width, height, top hay margin khiến trình duyệt phải dàn lại trang ở mỗi khung hình, có thể bị giật trên điện thoại yếu. Để di chuyển một thứ gì đó, hãy ưu tiên transform: translate() thay vì left hay margin. Trang transform giải thích các hàm này.

Lỗi thường gặp

  • transition chỉ nằm trong quy tắc :hover. Hiệu ứng chuyển động khi vào nhưng giật về khi hết hover. Hãy đặt transition trong quy tắc gốc.
  • Thời lượng thiếu đơn vị. transition: opacity 300 không hợp lệ. Hãy viết 300ms hoặc 0.3s.
  • transition: all. Nó tạo chuyển động cho mọi thuộc tính thay đổi, kể cả những thuộc tính bạn không định làm, và có thể khiến các thay đổi bố cục bị chậm chạp. Hãy liệt kê cụ thể các thuộc tính.
  • Tưởng display: none sẽ mờ dần. display đổi ngay lập tức. Hãy làm mờ opacity (và đặt visibility: hidden khi hiệu ứng mờ kết thúc).
  • Transition tới height: auto. Nó sẽ nhảy cái rụp. Hãy dùng kỹ thuật grid-template-rows ở trên.
  • Thời lượng dài cho tương tác nhỏ. Bất cứ thứ gì dài hơn khoảng 400ms trên nút hay menu đều tạo cảm giác chậm.

Câu hỏi thường gặp

CSS transition hoạt động thế nào?

Bạn khai báo trên phần tử những thuộc tính nào cần chuyển động và trong bao lâu, ví dụ transition: background-color 0.3s ease;. Khi giá trị của thuộc tính đó thay đổi (qua :hover, một class hoặc JavaScript), trình duyệt sẽ chuyển dần từ giá trị cũ sang giá trị mới thay vì đổi ngay lập tức.

Thứ tự các giá trị trong cách viết gọn transition là gì?

transition: property duration timing-function delay;, ví dụ transition: opacity 0.3s ease-in 0.1s;. Quy tắc bắt buộc duy nhất là giá trị thời gian đầu tiên là thời lượng, giá trị thứ hai là độ trễ. Ngăn cách nhiều transition bằng dấu phẩy.

Vì sao CSS transition không hoạt động?

Các nguyên nhân thường gặp: transition chỉ nằm trong quy tắc :hover (nên lúc vào thì có chuyển động, lúc ra thì giật về), thuộc tính đó không tạo chuyển động được (display, hoặc height thành auto), thời lượng thiếu đơn vị (0.3 thay vì 0.3s), hoặc giá trị thay đổi đúng lúc phần tử vừa được thêm vào trang.

Có thể transition height: auto không?

Không thể chỉ bằng một transition height thông thường trên mọi trình duyệt: nội suy tới auto cần thuộc tính mới interpolate-size, vốn chưa được hỗ trợ ở mọi nơi. Các cách xử lý phổ biến là tạo chuyển động cho grid-template-rows từ 0fr sang 1fr trên một lớp bọc dạng grid, hoặc tạo chuyển động cho max-height tới một giá trị lớn hơn nội dung.

Transition và animation trong CSS khác nhau thế nào?

Transition chạy một lần, giữa hai giá trị, khi một thuộc tính thay đổi. Animation dùng @keyframes, có thể có nhiều bước, tự chạy khi trang tải xong và có thể lặp lại.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu