Menu của bạn trông rất đẹp. Dropdown animation mượt mà, hover state bóng bẩy, mobile layout hoàn hảo từng điểm. Nhưng mỗi khi chạy Lighthouse test, Google báo CSS của bạn đang block rendering. LCP trên mobile đứng ở 3.2 giây, diagnostics bảo loại bỏ render-blocking stylesheets có thể tiết kiệm 800 milliseconds. Bạn không chắc điều đó có nghĩa gì hoặc cách sửa mà không làm hỏng design.
Vấn đề không phải ở design. Vấn đề ở cách delivery. Browser sẽ không vẽ một pixel nào cho đến khi tất cả CSS trong document head được download và parse xong. Nếu menu của bạn tải stylesheet 50KB, và network chậm, toàn bộ page ở trạng thái trắng trong khi browser chờ. Hero image đã sẵn sàng. Headline đã sẵn sàng. Nhưng chúng ở trạng thái vô hình vì browser vẫn đang xử lý menu styles.
Bài viết này giải thích cách CSS block rendering, menu styles nào cần tải trước, và cách chia stylesheet để phần critical load ngay lập tức còn phần còn lại tải sau khi page đã hiển thị.
- Tất cả external CSS files được link trong
<head>đều block rendering cho đến khi download và parse xong. - Inline critical CSS (các style cần cho above-the-fold content) eliminates network round trip.
- Hầu hết menu CSS không critical—chỉ layout structure và spacing cần tải trước.
- Hover effects, animations, và dropdown styles có thể tải sau initial paint mà không ảnh hưởng user experience.
- Một menu được optimize tốt tải 2-5KB inline CSS và defer phần còn lại.
Cách CSS Block Critical Rendering Path
Critical rendering path là chuỗi bước mà browser thực hiện để biến HTML, CSS, và JavaScript thành visible pixels trên màn hình. Các bước là: download HTML, parse HTML, download CSS, parse CSS, build render tree, calculate layout, paint pixels.
CSS block rendering theo design. Browser sẽ không vẽ gì cho đến khi tất cả stylesheets trong document head được load và parse đầy đủ. Điều này ngăn chặn Flash of Unstyled Content (FOUC), nơi page xuất hiện với default browser styles trong một phần giây trước khi real styles áp dụng.
Dưới đây là timeline cho một Shopify store điển hình với external menu stylesheet:
- Browser download HTML (200ms trên 4G)
- Browser parse HTML, gặp
<link rel="stylesheet" href="menu.css"> - Browser bắt đầu download
menu.css(300ms cho file 40KB trên 4G) - Browser hoàn thành download và parse
menu.css(50ms parse time trên mid-range mobile) - Browser bây giờ có thể bắt đầu vẽ page
Tổng thời gian đến first paint: 550ms, chỉ vì menu CSS. Thêm stylesheet chính của theme, bạn đang nhìn vào hơn một giây delay trước khi bất cứ thứ gì xuất hiện.
Theo Google’s web.dev documentation về render-blocking resources, eliminating hoặc deferring CSS mà không cần ngay lập tức là một trong những cách hiệu quả nhất để improve LCP và First Contentful Paint.
Cái Gì Tính Là Critical Menu CSS
Không phải tất cả menu styles cần tải trước first paint. Chỉ các style cần để render above-the-fold menu mà không layout shift là critical. Mọi thứ khác có thể tải sau.
Critical (phải tải trước)
- Layout structure: Display properties, flexbox/grid rules, positioning cho menu container.
- Spacing: Padding, margin, height, width để reserve đúng amount of space.
- Basic visibility: Display/visibility rules để menu xuất hiện ở đúng chỗ.
- Font size và line height: Prevents text từ reflow khi full stylesheet tải.
Non-critical (có thể defer)
- Colors và backgrounds: Menu có thể render với default colors ban đầu mà không gây layout shift.
- Hover effects và transitions: Chỉ áp dụng khi interaction, không trên initial load.
- Dropdown styles: Trên desktop, dropdowns ẩn cho đến khi user hover. Trên mobile, ẩn cho đến khi user tap hamburger. Các style này có thể tải sau khi page visible.
- Icons và decorative elements: Menu chevrons, divider lines, badge styles—tất cả non-essential cho initial render.
Goal là inline đủ CSS để prevent layout shift và defer phần còn lại.
Inline Critical CSS: Khi Nào Và Cách Thế Nào
Inline CSS nghĩa là viết nó trực tiếp vào <style> tag trong HTML, thay vì link tới external file. Điều này eliminates network round trip, là nguồn chính gây render-blocking delay.
Dưới đây là ví dụ về critical inline CSS cho navigation menu:
<style>
.menu-container {
display: flex;
align-items: center;
height: 60px;
padding: 0 20px;
}
.menu-nav {
display: flex;
gap: 24px;
}
.menu-link {
font-size: 16px;
line-height: 1.5;
text-decoration: none;
}
@media (max-width: 768px) {
.menu-nav { display: none; }
.menu-toggle { display: block; }
}
</style>
Đây khoảng 300 bytes. Nó reserve space đúng cho menu, prevent layout shift, và ensure menu structure đã sẵn sàng trước khi page paint. Phần còn lại của menu styles—colors, hover effects, dropdown animations—load từ external stylesheet sau initial paint.
Khi Nào Inline
Inline critical CSS khi:
- CSS nhỏ (dưới 5KB như rough guideline).
- Các style cần cho above-the-fold content trên mỗi page.
- Network latency là chi phí lớn hơn parse cost.
Với navigation menus, inline gần như luôn là lựa chọn đúng. Menu xuất hiện trên mỗi page, và critical subset của styles rất nhỏ.
Khi Không Inline
Không inline CSS nếu:
- Stylesheet lớn (trên 10KB). Inline CSS lớn sẽ bloat HTML và có thể làm chậm HTML parsing.
- Các style chỉ cần trên specific pages. Inline page-specific CSS trên mỗi page lãng phí bandwidth.
- CSS thay đổi thường xuyên. Inline CSS không được cache riêng—nó là phần HTML, nên mỗi HTML request include CSS.
Với menu apps có extensive styling (mega menus có hình ảnh, complex animations, multiple layout modes), inline chỉ layout structure và defer phần còn lại.
Load Non-Critical CSS Mà Không Block Render
Khi đã identify critical CSS và inline nó, bước tiếp theo là load phần còn lại của CSS mà không block render. Có hai approaches phổ biến.
Approach 1: Preload và Swap
Dùng <link rel="preload"> để download stylesheet trong background, rồi apply nó asynchronously.
<link rel="preload" href="menu.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="menu.css"></noscript>
preload bảo browser fetch menu.css với high priority nhưng không block rendering. onload event swap rel="preload" thành rel="stylesheet", apply styles khi file hoàn thành download. <noscript> fallback ensure styles load normally nếu JavaScript disabled.
Approach này được support rộng rãi và hoạt động trong tất cả modern browsers.
Approach 2: Media Query Trick
Load stylesheet với media query không match, rồi swap nó thành all sau load.
<link rel="stylesheet" href="menu.css" media="print" onload="this.media='all'">
media="print" attribute bảo browser stylesheet chỉ dành cho print, nên không block screen rendering. Khi file tải, onload event thay media query thành all, apply styles tới screen.
Đây là hack, nhưng hoạt động đáng tin cậy và cần ít JavaScript hơn approach preload.
Chia Stylesheet Menu Của Bạn
Hầu hết Shopify menu apps ship với một single monolithic CSS file bao gồm layout, colors, animations, responsive breakpoints, và icon styles. Để optimize critical path, bạn cần chia file này thành hai phần: critical và non-critical.
Dưới đây là practical workflow.
Bước 1: Identify Critical Selectors
Mở Chrome DevTools, đi tới Coverage tab (dưới More Tools), và reload page. Chrome sẽ show bạn CSS rules nào được dùng trong initial render. Mọi thứ khác là non-critical.
Với navigation menu, critical selectors thường bao gồm:
.menu-container,.menu-nav,.menu-logo- Layout properties:
display,flex,grid,position,width,height,padding,margin - Responsive breakpoints cho above-the-fold layout
Bước 2: Extract Critical CSS
Copy critical selectors vào file mới, menu-critical.css. Minify nó (remove whitespace và comments). Kết quả nên là 2-5KB.
Bước 3: Inline Critical CSS
Convert menu-critical.css thành <style> block trong theme’s <head>. Trong Shopify Liquid:
<style>
{% include 'menu-critical.css' %}
</style>
Hoặc paste CSS trực tiếp vào <style> tag.
Bước 4: Defer Full Stylesheet
Load full menu.css asynchronously dùng một trong các methods mô tả ở trước.
<link rel="preload" href="menu.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
Bây giờ critical layout styles load ngay (không network delay), và phần còn lại load song song mà không block page.
Shopify-Specific CSS Optimization
Shopify themes dùng file.css filter để load CSS. By default, nó generates standard <link rel="stylesheet"> tag, là render-blocking.
Để make stylesheet non-blocking, replace filter với manual tag:
<link rel="preload" href="menu.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="menu.css"></noscript>
Với theme sections load CSS dynamically, Shopify’s Section Rendering API không automatically apply preload strategies. Nếu menu của bạn là section, bạn cần ensure critical CSS được inline trong main theme.liquid file, không trong section’s own stylesheet.
Một số Shopify menu apps, như Navi+, automatically chia CSS thành critical và non-critical parts và handle async loading cho bạn. Nếu current menu app của bạn không support điều này, đó là giá trị hỏi developer thêm nó hoặc switch sang tool đã làm rồi.
Đo Lường Impact
Trước và sau khi optimize menu CSS của bạn, đo improvement với Lighthouse hoặc PageSpeed Insights. Nhìn ba metrics cụ thể:
- First Contentful Paint (FCP): Thời gian khi first text hoặc image xuất hiện. Inline critical CSS reduce FCP bằng cách eliminating render-blocking network requests.
- Largest Contentful Paint (LCP): Thời gian khi largest visible element hoàn thành render. Removing render-blocking CSS cho phép hero image hoặc headline paint sớm hơn.
- Cumulative Layout Shift (CLS): Measure visual stability. Properly inline critical CSS reserve space cho menu, prevent nó từ shift page content xuống khi load.
Bạn nên thấy FCP và LCP drop 200-600ms trên mobile sau khi defer non-critical menu CSS. Nếu không thấy improvement, check xem có other render-blocking stylesheets (theme CSS, app CSS) vẫn cần optimize.
Sai lầm phổ biếnMột số merchants inline toàn bộ menu stylesheet để eliminate render-blocking, nhưng điều này backfire nếu file lớn. Một 50KB inline stylesheet bloat HTML, làm chậm HTML parsing, và prevent CSS từ being cached. Inline chỉ critical subset (2-5KB), và defer phần còn lại.
Mobile Matters More
Desktop connections nhanh. File CSS 40KB qua broadband thêm khoảng 50 milliseconds delay. Trên mobile, file tương tự qua 4G connection thêm 300 milliseconds. Trên slow 3G connection, có thể thêm 800 milliseconds.
Google’s Core Web Vitals được đo riêng biệt cho mobile và desktop, và mobile được weight nặng hơn trong search rankings vì hầu hết traffic là mobile. Optimize menu CSS của bạn cho mobile không phải tùy chọn—nó là baseline.
Test store của bạn trên real device qua real mobile connection, hoặc dùng Chrome DevTools với throttling enabled (Fast 3G hoặc Slow 3G). Bạn sẽ thấy true cost của render-blocking CSS, và improvement từ inline và defer trở nên obvious.
Cách Menu CSS Loading Tốt Trông Như Thế Nào
Một navigation menu được optimize tốt load CSS trong hai stages. Trước, một tiny inline block của critical CSS (2-5KB) định nghĩa layout structure, spacing, và responsive breakpoints. Đây load ngay lập tức như phần HTML. Thứ hai, full stylesheet (30-50KB) với colors, hover effects, animations, và dropdown styles, tải asynchronously dùng preload hoặc media query trick.
Page trở thành visible trong 1-2 giây, thậm chí trên slow mobile connection. Menu xuất hiện ở đúng vị trí mà không shift layout. Full styles áp dụng một fraction của giây sau, imperceptibly tới user nhưng measurably tới Google’s LCP calculation.
Đây không phải lý thuyết. Stores implement pattern này thường thấy mobile LCP improve 400-700 milliseconds, move từ “needs improvement” tới “good” trong Core Web Vitals reports. Menu vẫn trông và hoạt động giống hệt nhau, nhưng browser không còn phải chờ full stylesheet trước khi paint page.
Bài viết này là phần của hướng dẫn lớn hơn về Menu và LCP: cách navigation làm chậm largest contentful paint của bạn.