Tại sao một số ảnh động bị chậm?

Các trình duyệt hiện đại có thể tạo ảnh động cho 2 thuộc tính CSS với chi phí thấp: transformopacity. Nếu bạn tạo hiệu ứng cho bất kỳ thành phần nào khác, thì có thể bạn sẽ không đạt được tốc độ 60 khung hình/giây (FPS) mượt mà. Bài đăng này giải thích lý do tại sao lại như vậy.

Hiệu suất và tốc độ khung hình của ảnh động

Mọi người đều chấp nhận rằng tốc độ khung hình mục tiêu là 60 khung hình/giây khi tạo hiệu ứng động cho bất kỳ nội dung nào trên web. Tốc độ khung hình này sẽ đảm bảo ảnh động của bạn trông mượt mà. Trên web, khung hình là khoảng thời gian cần thiết để hoàn thành tất cả công việc cần thiết nhằm cập nhật và vẽ lại màn hình. Nếu mỗi khung hình không hoàn thành trong vòng 16,7 mili giây (1000 mili giây / 60 ≈ 16,7), thì người dùng sẽ nhận thấy độ trễ.

Quy trình kết xuất

Để hiển thị nội dung trên một trang web, trình duyệt phải trải qua các bước tuần tự sau:

  1. Kiểu: Tính toán các kiểu áp dụng cho các phần tử.
  2. Bố cục: Tạo hình học và vị trí cho từng phần tử.
  3. Paint (Vẽ): Điền các pixel cho từng phần tử.
  4. Kết hợp: Tách các phần tử thành các lớp và vẽ các lớp đó lên màn hình.

Bốn bước này được gọi là quy trình kết xuất của trình duyệt.

Khi bạn tạo hiệu ứng cho một thành phần trên trang đã tải, các bước này phải diễn ra lại. Quá trình này bắt đầu từ bước cần thay đổi để cho phép ảnh động diễn ra.

Như đã đề cập trước đó, các bước này diễn ra theo trình tự. Ví dụ: nếu bạn tạo hiệu ứng cho một đối tượng thay đổi bố cục, thì các bước vẽ và kết hợp cũng phải chạy lại. Do đó, việc tạo ảnh động cho một thành phần thay đổi bố cục sẽ tốn kém hơn so với việc tạo ảnh động cho một thành phần chỉ thay đổi quá trình kết hợp.

Tạo ảnh động cho các thuộc tính bố cục

Các thay đổi về bố cục liên quan đến việc tính toán hình học (vị trí và kích thước) của tất cả các phần tử chịu ảnh hưởng của thay đổi. Nếu bạn thay đổi một phần tử, thì hệ thống có thể cần tính toán lại hình học của các phần tử khác. Ví dụ: nếu bạn thay đổi chiều rộng của phần tử <html>, thì mọi phần tử con của phần tử đó đều có thể bị ảnh hưởng. Do cách các phần tử tràn và ảnh hưởng lẫn nhau, nên các thay đổi ở xa hơn trong cây đôi khi có thể dẫn đến các phép tính bố cục cho đến tận đầu.

Cây phần tử hiển thị càng lớn thì thời gian cần thiết để thực hiện các phép tính bố cục càng lâu.

Tạo ảnh động cho các thuộc tính sơn

Paint (Vẽ) là quá trình xác định thứ tự vẽ các phần tử lên màn hình. Đây thường là nhiệm vụ chạy lâu nhất trong tất cả các nhiệm vụ trong quy trình.

Phần lớn hoạt động vẽ trong các trình duyệt hiện đại được thực hiện trong trình chuyển đổi raster phần mềm. Tuỳ thuộc vào cách các phần tử trong ứng dụng của bạn được nhóm thành các lớp, ngoài phần tử đã thay đổi, các phần tử khác cũng có thể cần được vẽ.

Tạo ảnh động cho các thuộc tính kết hợp

Tổng hợp là quá trình phân tách trang thành các lớp, chuyển đổi thông tin về cách trang sẽ xuất hiện thành các pixel (raster hoá) và ghép các lớp lại với nhau để tạo một trang (tổng hợp).

Đây là lý do thuộc tính opacity có trong danh sách những thứ có chi phí thấp để tạo hiệu ứng chuyển động. Miễn là thuộc tính này nằm trong lớp riêng, GPU có thể xử lý các thay đổi đối với thuộc tính này trong bước kết hợp. Trình duyệt dựa trên Chromium và WebKit tạo một lớp mới cho mọi phần tử có hiệu ứng chuyển đổi hoặc ảnh động CSS trên opacity.

Lớp là gì?

Bằng cách đặt những thứ sẽ được tạo ảnh động hoặc chuyển đổi lên một lớp mới, trình duyệt chỉ cần vẽ lại những mục đó chứ không cần vẽ lại mọi thứ khác. Có thể bạn đã quen với khái niệm về lớp trong Photoshop. Lớp này chứa một nhóm các phần tử có thể di chuyển cùng nhau. Các lớp kết xuất của trình duyệt cũng tương tự như ý tưởng đó.

Mặc dù trình duyệt đưa ra quyết định khá tốt về những phần tử nên nằm trên một lớp mới, nhưng nếu trình duyệt bỏ lỡ một phần tử, thì bạn có thể buộc trình duyệt tạo lớp. Bạn có thể tìm hiểu về vấn đề này trong bài viết Cách tạo ảnh động có hiệu suất cao. Tuy nhiên, bạn nên cẩn thận khi tạo các lớp mới vì mỗi lớp đều sử dụng bộ nhớ. Trên các thiết bị có bộ nhớ hạn chế, việc tạo các lớp mới có thể gây ra nhiều vấn đề về hiệu suất hơn vấn đề mà bạn đang cố gắng giải quyết. Ngoài ra, bạn cần tải hoạ tiết của từng lớp lên GPU. Do đó, bạn có thể gặp phải các hạn chế về băng thông giữa CPU và GPU.

Hiệu suất CSS so với JavaScript

Bạn có thể thắc mắc: về hiệu suất, có nên dùng CSS hay JavaScript cho ảnh động?

Ảnh động dựa trên CSS và Ảnh động trên web (trong những trình duyệt hỗ trợ API này) thường được xử lý trên một luồng được gọi là luồng trình kết hợp. Điều này khác với luồng chính của trình duyệt, nơi thực thi việc tạo kiểu, bố cục, vẽ và JavaScript. Điều này có nghĩa là nếu trình duyệt đang chạy một số tác vụ tiêu tốn nhiều tài nguyên trên luồng chính, thì các ảnh động này có thể tiếp tục chạy mà không bị gián đoạn.

Như đã giải thích trong bài viết này, trong nhiều trường hợp, các thay đổi khác đối với hoạt động biến đổi và độ mờ cũng có thể được xử lý bằng luồng kết hợp.

Nếu có bất kỳ ảnh động nào kích hoạt thao tác vẽ, bố cục hoặc cả hai, thì luồng chính sẽ phải thực hiện công việc. Điều này đúng cho cả ảnh động CSS và JavaScript, đồng thời chi phí chung của bố cục hoặc hoạt động kết xuất có thể sẽ lấn át mọi hoạt động liên quan đến việc thực thi CSS hoặc JavaScript, khiến câu hỏi này trở nên không cần thiết.