CSS/JS chặn hiển thị và cách nạp bất đồng bộ
Hướng dẫn chi tiết cách khắc phục lỗi CSS và JavaScript chặn hiển thị (render-blocking) bằng async, defer, preload và critical CSS giúp tối ưu Core Web Vitals.
Khi lập trình một trang web, hầu hết sinh viên và người mới bắt đầu thường gặp phải tình trạng trang web mất 3 đến 5 giây mới hiển thị được nội dung đầu tiên. Nguyên nhân phổ biến nhất gây ra hiện tượng trắng màn hình tạm thời này chính là các tệp CSS và JavaScript chặn hiển thị (Render-Blocking Resources). Trình duyệt khi tải trang HTML sẽ tạm dừng việc dựng giao diện ngay khi bắt gặp một tệp CSS hoặc JS nằm ở thẻ head chưa được xử lý bất đồng bộ. Điều này khiến chỉ số First Contentful Paint (FCP) và Largest Contentful Paint (LCP) tăng cao, ảnh hưởng trực tiếp đến trải nghiệm người dùng cũng như điểm số SEO trên Google Search Console.
Trong bài viết này, đội ngũ kỹ thuật của LuckySEO sẽ hướng dẫn bạn bản chất của luồng dựng trang (Critical Rendering Path) và cách xử lý triệt để tài nguyên chặn hiển thị. Chúng tôi sẽ đi sâu vào việc so sánh thuộc tính async và defer cho JavaScript, kỹ thuật tách Critical CSS để nhúng trực tiếp vào thẻ HTML, cùng với phương pháp sử dụng link rel=preload hợp lý. Nhờ những giải pháp thực chiến này, bạn có thể dễ dàng tối ưu điểm Google PageSpeed Insights cho website của mình lên mức trên 90 điểm mà không cần phải sử dụng các plugin phức tạp hay tốn chi phí đắt đỏ.
Tài nguyên chặn hiển thị (Render-Blocking) là gì và vì sao nó gây hại?
Về bản chất, trình duyệt xử lý tệp HTML từ trên xuống dưới theo thứ tự tuyến tính. Khi gặp thẻ script src='app.js' hoặc link rel='stylesheet' href='style.css', trình duyệt sẽ dừng việc phân tích ngữ pháp HTML để gửi yêu cầu mạng tải tệp đó về, sau đó biên dịch và thực thi xong rồi mới tiếp tục phân tích HTML. Nếu tệp CSS hoặc JS của bạn có dung lượng lớn (ví dụ tệp CSS nặng 300KB hoặc thư viện jQuery 100KB), toàn bộ quá trình hiển thị nội dung cho người dùng sẽ bị đóng băng. Điều này làm giảm đáng kể tốc độ phản hồi và khiến tỷ lệ thoát trang gia tăng nhanh chóng.
⚠ Lưu ý từ LuckySEO về Core Web Vitals
Google sử dụng chỉ số FCP (dưới 1.8 giây) và LCP (dưới 2.5 giây) làm tiêu chí xếp hạng SEO chính thức. Việc để các tệp CSS/JS chặn hiển thị có thể khiến FCP vượt quá 3.5 giây, đẩy website của bạn vào nhóm 'Cần cải thiện' hoặc 'Kém' trên Google Search Console.
Tối ưu JavaScript: Phân biệt và sử dụng Async vs Defer đúng cách
Để ngăn chặn JavaScript làm gián đoạn quá trình phân tích HTML, HTML5 cung cấp hai thuộc tính quan trọng cho thẻ script là async và defer. Cả hai thuộc tính này đều giúp trình duyệt tải tệp script về một cách bất đồng bộ trong nền mà không làm dừng việc đọc HTML. Tuy nhiên, thời điểm thực thi mã lệnh của chúng lại hoàn toàn khác nhau. Việc chọn sai thuộc tính có thể dẫn đến lỗi xung đột thư viện, chẳng hạn như lỗi 'jQuery is not defined' rất thường gặp ở các bạn sinh viên khi mới làm quen với lập trình web.
- ✓Thuộc tính defer: Tải tệp JS trong nền và chỉ thực thi sau khi trình duyệt đã phân tích xong toàn bộ HTML (ngay trước sự kiện DOMContentLoaded). Các script có defer sẽ thực thi theo đúng thứ tự khai báo trong HTML. Phù hợp cho các script phụ thuộc lẫn nhau như jQuery và plugin phụ thuộc. Cú pháp: <script src='main.js' defer></script>.
- ✓Thuộc tính async: Tải tệp JS trong nền và thực thi ngay lập tức ngay khi tải xong, tạm dừng việc phân tích HTML tại thời điểm đó. Các script có async không đảm bảo thứ tự thực thi. Phù hợp cho mã độc lập như Google Analytics, Facebook Pixel. Cú pháp: <script src='analytics.js' async></script>.
Tối ưu CSS: Kỹ thuật Critical CSS và Preload chuẩn SEO
Khác với JavaScript có thuộc tính defer, mặc định mọi tệp CSS ngoại trú (link rel='stylesheet') đều là tài nguyên chặn hiển thị bắt buộc, vì trình duyệt không thể vẽ giao diện nếu chưa biết quy tắc tạo kiểu. Giải pháp tối ưu nhất hiện nay là kỹ thuật Critical CSS. Bạn sẽ tách toàn bộ các quy tắc CSS cần thiết để hiển thị phần màn hình đầu tiên (Above-The-Fold - phần người dùng nhìn thấy ngay mà chưa cần cuộn trang) và nhúng trực tiếp chúng vào thẻ style trong head. Phần CSS còn lại cho các phần bên dưới sẽ được nạp bất đồng bộ.
Để nạp tệp CSS không quan trọng (Non-critical CSS) một cách bất đồng bộ, bạn kết hợp thuộc tính rel='preload' với việc thay đổi thuộc tính media. Cụ thể, bạn khai báo: <link rel='preload' href='non-critical.css' as='style' onload="this.onload=null;this.rel='stylesheet'">. Khi áp dụng kỹ thuật này, trình duyệt sẽ tải tệp CSS trong nền mà không chặn việc vẽ giao diện. Ngay khi tệp tải xong, sự kiện onload sẽ chuyển thẻ link thành một bảng kiểu (stylesheet) chính thức để áp dụng các quy tắc còn lại cho trang web mà không gây trễ FCP.
Quy trình 4 bước tối ưu nạp bất đồng bộ cho website mới
Các bước triển khai nạp bất đồng bộ chuẩn kỹ thuật
💡 Mẹo nhỏ tránh lỗi FOUT (Flash of Unstyled Content)
Khi sử dụng Critical CSS, hãy đảm bảo bạn không bỏ sót các style định hình bố cục cơ bản như width, height, flexbox của phần header và banner đầu trang. Nếu thiếu, trang web sẽ bị giật khung hình (Layout Shift) khi tệp CSS chính được nạp xong, làm giảm điểm CLS nghiêm trọng.
Bạn thường gặp phải khó khăn gì nhất khi tối ưu tài nguyên chặn hiển thị trên website của mình?
Nếu bạn có một tệp JavaScript A phụ thuộc vào thư viện jQuery, bạn nên nhúng tệp A bằng thẻ nào sau đây?
Cần triển khai SEO bài bản?
Đội ngũ LuckySEO đồng hành cùng bạn từ audit đến tăng trưởng bền vững.
Nhận tư vấn miễn phí