Tìm hiểu về Render Blocking CSS và đo page rendering time với Chrome Performance API

performanceperformance

CSS được browser xem là 1 trong những render blocking resources - những tài nguyên mà trang của bạn bắt buộc phải tải thì người dùng mới có thể nhìn thấy nội dung được

Tại sao nên tránh Render Blocking CSS

  • Render blocking CSS sẽ làm chậm việc hiển thị website của bạn đến người dùng

  • Mỗi file CSS mà website của bạn tải sẽ tăng thêm thời gian vào first-paint của page, có nghĩa là user sẽ phải đợi lâu hơn để nhìn thấy content nếu trang của bạn phải tải nhiều CSS


render-blocking-cssrender-blocking-css

CSS ảnh hưởng rất nhiều đến thời gian hiển thị trang

Khi bắt đầu tải trang, browser sẽ luôn tự động tải tất cả các file CSS, không quan tâm đến việc nó có block quá trình render hay không!

Vậy phải làm thế nào để hạn chế được render blocking css ?

Solutions

Nếu như bạn nhận thấy trang của mình có những CSS mà chỉ sử dụng trong 1 vài điều kiện nhất định ví dụ như style cho content bên trong 1 modaluser phải click để open modal mới thấy, content bên trong tab không hiển thị đầu tiên, hoặc những style chỉ apply riêng cho large monitor hoặc mobile devices...

Thì đây là 1 số cách có thể giúp trang của bạn tải nhanh hơn

Sử dụng media attribute

Khi muốn load css vào web page của mình chúng ta sẽ sử dụng thẻ link như thế này

<link href="style.css" rel="stylesheet" />

<link href="print.css" rel="stylesheet" />

<link href="style.mobile.css" rel="stylesheet" />

Browser sau khi load xong HTML sẽ tải thêm 3 file CSS này nữa và chỉ hiển thị nội dung sau khi đã tải xong tất cả

Tuy nhiên print.css chỉ dùng khi in document (Ctrl/Cmd + P) và style.mobile.css là những style chỉ apply trên mobile mà thôi

Trong trường hợp này chúng ta có thể sử dụng media attribute

<link href="style.css" rel="stylesheet" />

<link href="print.css" media="print" rel="stylesheet" />

<link href="style.mobile.css" media="(max-width: 568px)" rel="stylesheet" />

Lúc này browser sẽ hiểu rằng chỉ cần tải xong file style.css là ngay lập tức có thể hiển thị nội dung trang cho người dùng mà không cần biết 2 file còn lại đã tải xong hay chưa

Đối với link sử dụng media attribute:

  • media="print": những style trong file này sẽ chỉ apply khi in document, không cần cho render nên sẽ không block lần render đầu tiên khi tải trang

  • media="(max-width: 568px)": những style này chỉ apply trên những device với max-witdh=568px và cũng không block lần render đầu tiên khi tải trang trên desktop/tablet device

Sử dụng media attribute chúng ta có thể điều chỉnh việc hiển thị trang theo các trường hợp cụ thể như: sau khi đã render xong, điều chỉnh kích thước màn hình, thay đổi hướng thiết bị (ngang/dọc)...

Giá trị của media bắt buộc phải là 1 media type hoặc media query, rất hữu ích khi cần load các external stylesheets - nó hỗ trợ browser lựa chọn được những CSS cần thiết nhất cho lần render đầu tiên

Combine css or inline css

1 cách khá hiệu quả là các bạn có thể để trực tiếp CSS vào trong 1 thẻ style trên header của document nếu CSS không quá to, cách này cải thiện performance rất tốt khi chỉ cần DOM load xong là có thể hiển thị ngay được rồi

Hoặc có thể hạn chế tải nhiều file CSS quá. Thông thường khi code các dev sẽ có xu hướng tách ra nhiều file CSS khác nhau theo component, module... để dễ quản lý, tuy nhiên việc load nhiều file CSS sẽ lâu hơn so với chỉ load 1 hoặc 2 file

inline-cssinline-css

1 trong những kĩ thuật giúp Gatsby site tải rất nhanh chính là Inline CSS

Performance API

Bây giờ chúng ta hãy thử đo đạc page rendering time sau khi áp dụng 1 số kĩ thuật để tránh Render Blocking CSS với Chrome Perfomance API nhé

Mình có viết 1 ví dụ đơn giản để các bạn có thể hiểu về Render Blocking CSS ở đây: https://hta218.github.io/render-blocking-css-example/

Trong ví dụ mình có load 2 file CSS và so sánh page rendering time với 2 màn hình có device-width lớn hơn và nhỏ hơn 800px

<link rel="stylesheet" href="tailwind.css" media="(min-width: 800px)" />

<link rel="stylesheet" href="bootstrap.css" media="(min-width: 800px)" />

Để sử dụng Performance API thì cần chú ý kiểm tra kĩ browser compatibility

if ('PerformanceObserver' in window) {

try {

// Create PerformanceObserver instance

const perfObsever = new PerformanceObserver((perf) => {

const perfEntries = perf.getEntriesByType('paint')

perfEntries.forEach(({ name, startTime }) => {

// Get the result inside this callback

console.log(`The time to ${name} was ${startTime} milliseconds.`)

})

})

// observe "paint" event

perfObsever.observe({ entryTypes: ['paint'] })

} catch (err) {

console.error(err)

}

} else {

// Remember to check the browser compatibility before using this API

console.log("Performance API isn't supported!")

}

Có nhiều Performance metric khác nhau, trong trường hợp này mình sử dụng PerformancePaintTiming

Để thấy rõ hơn kết quả các bạn có thể mở chrome devtool lên, throttle internetCPU speed cho giống với điều kiện ở máy user hơn nhé

Với màn hình >800px (ví dụ cho load tất cả các CSS trước first page render)

css-block-rendercss-block-render

Chúng ta cần hơn 6 giây cho first paint (sau khi tất cả CSS load xong) - tương đương với user phải đợi 6s mới thấy nội dung của page

Với trường hợp chỉ cần load 1 file CSS cho first paint (các file còn lại vẫn được load nhưng không dùng đến hoặc không cần dùng cho lần render đầu tiên)

css-not-block-rendercss-not-block-render

User nhìn thấy content sớm hơn 2 giây, có thể thấy page render ngay cả khi 2 file CSS còn lại vẫn chưa load xong

Kết quả đo đạc với Performance API được tổng hợp lại

render-resultrender-result

Hoặc đơn giản hơn, các bạn có thể sử dụng trực tiếp PerformancePaintTiming API

if (window.performance) {

const performance = window.performance;

const perfEntries = performance.getEntriesByType('paint');

perfEntries.forEach({ name, startTime } => {

console.log(`The time to ${name} was ${startTime} milliseconds.`);

});

} else {

console.log("Performance timing isn't supported.");

}

Kết bài

Có thể thấy sự khác biệt rõ rệt với page rendering time, ảnh hưởng trực tiếp đến user's experience khi webpage phải tải quá nhiều CSS không cần thiết, vì vậy chúng ta cần phải rất chú ý đến resource này.

Có nhiều biện pháp để tránh Render Blocking CSS như: sử dụng media type hoặc media query, combine CSS, inline CSS, những thay đổi này tuy nhỏ nhưng ảnh hưởng rất tốt đến perfomance

Refs