Tối ưu browser rendering: Style và độ sâu DOM

60fps là mục tiêu cuối cùng của một web page "mượt"

Ở bài viết trước chúng ta đã tìm hiểu về khía niệm độ mượt của ứng dụng web và một yếu tố ảnh hưởng lớn đến độ mượt, đó là tác vụ reflow. Trong bài viết này chúng ta sẽ cùng tìm hiểu các khía cạnh khác ảnh hưởng đến độ mượt của ứng dụng web nói chung và ảnh hưởng liên đới đến reflow nói riêng, cụ thể là Tối ưu độ sâu DOMtối ưu sử dụng CSS selector (Style trong rendering pipeline).

Điều cần chú ý:

Tất cả các hành động dính dáng đến style thay đổi DOM bằng việc thêm, xoá phần tử, thay đổi thuộc tính, class hoặc animation sẽ đều khiến trình duyệt tính toán lại style và (trong nhiều trường hợp) tính toán lại layout (chính là hành vi reflow đã đề cập trong bài viết trước).

Độ sâu của DOM (DOM Depth)

Độ sâu DOM ảnh hưởng như thế nào?

Độ sâu của DOM ảnh hưởng đến nhiều đối tượng như server, network, client run time, client memory. Tuy nhiên (tất nhiên) ở đây chúng ta sẽ chỉ đề cập đến client run time. Tại sao DOM quá sâu sẽ gây ảnh hưởng performance. Trong rất nhiều trường hợp, việc update một DOM node sẽ kéo theo update tất cả các DOM node con, đồng nghĩa việc việc tất cả các DOM bị update liên đới sẽ phải được tính toán lại (reflow). Nếu DOM của chúng ta quá sâu, đồng nghĩa với việc việc tính toán sẽ trở nên phức tạp hơn.

Cây DOM như thế nào là phù hợp

Vậy sâu bao nhiêu thì phù hợp. Sau đây là các con số tham khảo từ Google về một case DOM hợp lý:

Một vài lời khuyên

CSS selector

Các giai đoạn tính toán style

Tối ưu như thế nào.

Giảm độ phức tạp của selector

Để giảm độ phức tạp của selector, cách đơn giản nhất là giảm độ phức tạp (độ sâu) của DOM. Nếu độ sâu của DOM đạt được con số tối ưu thì mặc định css selector cũng sẽ được tối ưu theo. Tuy nhiên, nếu chúng ta buộc phải làm việc với DOM sâu thì việc tối ưu selector là bắt buộc phải chú ý. Có một phương thức tổ chức CSS selector xoay quanh class name rất tốt cho việc tối ưu selector, đó chính là BEM.

Ví dụ, trong một số trường hợp, việc chạm tới phần tử cuối cùng sẽ trông như thế này

.box:nth-last-child(-n+1) .title {
  /* styles */
}

Thay vì dùng logic như trên, nếu đặt tên theo luật BEM, chúng ta có thể đặt:

.final-box-title {
  /* styles */
}

Cách đặt tên này sẽ giàm thiểu thời gian ghép cặp selector rất nhiều.

Việc sử dụng block naming rule của BEM cũng rất hữu ích. BEM khuyến nghị mỗi thằng nên có 1 class riêng. Và nếu cần target tới cấp bậc thấp hơn, hãy đặt tên dựa vào cấp bậc cha.

.list { }
.list__list-item { }

Giảm số lượng phần tử phải tính lại style.

Cái này thì có lẽ có thể bỏ qua với các trình duyệt hiện đại, vì chúng đang được tối ưu tốt cho việc phát hiện những phần tử nào thực sự cần tính toán lại dựa vào vị trí trong cây DOM. Nếu bạn muốn tìm hiểu thêm có thể đọc tại đây.

Chúng ta sẽ cùng tìm hiểu các yếu tố khác ảnh hưởng đến rendering performance trong phần tiếp theo.

Tham khảo:

Previous Post Next Post