[{"data":1,"prerenderedAt":1292},["ShallowReactive",2],{"content:\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Floading-non-critical-css-asynchronously":3,"surroundings:\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Floading-non-critical-css-asynchronously":1283},{"id":4,"title":5,"body":6,"description":1262,"extension":1263,"meta":1264,"navigation":1276,"path":1277,"seo":1278,"stem":1281,"__hash__":1282},"content\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Floading-non-critical-css-asynchronously\u002Findex.md","Loading Non-Critical CSS Asynchronously",{"type":7,"value":8,"toc":1243},"minimark",[9,14,42,45,213,218,247,251,257,263,269,279,283,288,420,424,526,530,611,614,618,621,744,748,751,755,762,891,895,898,902,908,1042,1053,1057,1064,1068,1097,1101,1118,1124,1130,1136,1140,1156,1165,1174,1183,1192,1201,1205,1228,1233,1236,1239],[10,11,13],"h1",{"id":12},"how-to-load-non-critical-css-asynchronously","How to Load Non-Critical CSS Asynchronously",[15,16,17,18,23,24,28,29,33,34,37,38,41],"p",{},"This guide is part of ",[19,20,22],"a",{"href":21},"\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002F","Critical CSS & Render-Blocking Resources",", within ",[19,25,27],{"href":26},"\u002Frendering-css-performance\u002F","Rendering & CSS Performance",". Once critical CSS is inlined, the full stylesheet must still load — but without blocking the first paint. HTML has no ",[30,31,32],"code",{},"async"," attribute for stylesheets, so several patterns exist: swapping a non-matching ",[30,35,36],{},"media"," attribute, preloading and switching ",[30,39,40],{},"rel",", splitting CSS by media query, and loading stylesheets from JavaScript. They differ in browser behaviour, priority, and how they fail.",[15,43,44],{},"The main risk is not technical failure but visual: if the async stylesheet contains rules for content visible on first paint, users see a flash of unstyled content (FOUC) and layout shifts when it applies. Async loading is only safe when paired with complete critical CSS, or when the deferred CSS really applies to content below the fold or in later interactions.",[15,46,47],{},[48,49,55,56,55,63,55,67,55,70,55,79,55,85,55,91,55,98,55,102,55,107,55,110,55,114,55,117,55,121,55,125,55,129,55,131,55,135,55,140,55,143,55,147,55,150,55,153,55,157,55,159,55,162,55,164,55,167,55,169,55,171,55,174,55,178,55,180,55,183,55,185,55,188,55,190,55,193,55,196,55,200,55,202,55,205,55,207,55,209,55,211,55],"svg",{"viewBox":50,"width":51,"role":52,"ariaLabel":53,"style":54},"0 0 760 228","100%","img","Comparison of patterns for loading CSS without blocking rendering, by priority, JavaScript dependency and fallback behaviour.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[57,58],"rect",{"className":59,"x":61,"y":61,"width":51,"height":51,"fill":62},[60],"svg-canvas","0","#ffffff",[64,65,66],"title",{},"Async CSS loading patterns",[68,69,53],"desc",{},[57,71],{"x":72,"y":72,"width":73,"height":74,"rx":75,"fill":76,"stroke":77,"style":78},"1","758","226","10","none","currentColor","stroke-opacity:0.18",[80,81,66],"text",{"x":82,"y":83,"fill":77,"style":84},"28.0","34.0","font-size:16px;font-weight:700",[57,86],{"x":82,"y":87,"width":88,"height":89,"rx":61,"fill":77,"stroke":77,"style":90},"56.0","188.3","30.0","fill-opacity:0.06;stroke-opacity:0.4",[80,92,97],{"x":93,"y":94,"fill":77,"style":95,"textAnchor":96},"38.0","75.5","font-size:12.5px;font-weight:700","start","Pattern",[57,99],{"x":100,"y":87,"width":101,"height":89,"rx":61,"fill":77,"stroke":77,"style":90},"216.3","171.9",[80,103,106],{"x":104,"y":94,"fill":77,"style":95,"textAnchor":105},"302.2","middle","Fetch priority",[57,108],{"x":109,"y":87,"width":101,"height":89,"rx":61,"fill":77,"stroke":77,"style":90},"388.2",[80,111,113],{"x":112,"y":94,"fill":77,"style":95,"textAnchor":105},"474.1","Needs JS",[57,115],{"x":116,"y":87,"width":101,"height":89,"rx":61,"fill":77,"stroke":77,"style":90},"560.1",[80,118,120],{"x":119,"y":94,"fill":77,"style":95,"textAnchor":105},"646.0","Fallback",[57,122],{"x":82,"y":123,"width":88,"height":89,"rx":61,"fill":76,"stroke":77,"style":124},"86.0","stroke-opacity:0.35",[80,126,128],{"x":93,"y":127,"fill":77,"style":95,"textAnchor":96},"105.5","media=print + onload swap",[57,130],{"x":100,"y":123,"width":101,"height":89,"rx":61,"fill":77,"stroke":77,"style":90},[80,132,134],{"x":104,"y":127,"fill":77,"style":133,"textAnchor":105},"font-size:12px","lowest",[57,136],{"x":109,"y":123,"width":101,"height":89,"rx":61,"fill":137,"stroke":138,"style":139},"#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[80,141,142],{"x":112,"y":127,"fill":77,"style":133,"textAnchor":105},"yes for swap",[57,144],{"x":116,"y":123,"width":101,"height":89,"rx":61,"fill":145,"stroke":145,"style":146},"#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[80,148,149],{"x":119,"y":127,"fill":77,"style":133,"textAnchor":105},"noscript link",[57,151],{"x":82,"y":152,"width":88,"height":89,"rx":61,"fill":76,"stroke":77,"style":124},"116.0",[80,154,156],{"x":93,"y":155,"fill":77,"style":95,"textAnchor":96},"135.5","rel=preload + onload rel swap",[57,158],{"x":100,"y":152,"width":101,"height":89,"rx":61,"fill":145,"stroke":145,"style":146},[80,160,161],{"x":104,"y":155,"fill":77,"style":133,"textAnchor":105},"high",[57,163],{"x":109,"y":152,"width":101,"height":89,"rx":61,"fill":137,"stroke":138,"style":139},[80,165,166],{"x":112,"y":155,"fill":77,"style":133,"textAnchor":105},"yes",[57,168],{"x":116,"y":152,"width":101,"height":89,"rx":61,"fill":145,"stroke":145,"style":146},[80,170,149],{"x":119,"y":155,"fill":77,"style":133,"textAnchor":105},[57,172],{"x":82,"y":173,"width":88,"height":89,"rx":61,"fill":76,"stroke":77,"style":124},"146.0",[80,175,177],{"x":93,"y":176,"fill":77,"style":95,"textAnchor":96},"165.5","Split by media query",[57,179],{"x":100,"y":173,"width":101,"height":89,"rx":61,"fill":77,"stroke":77,"style":90},[80,181,182],{"x":104,"y":176,"fill":77,"style":133,"textAnchor":105},"low for non-matching",[57,184],{"x":109,"y":173,"width":101,"height":89,"rx":61,"fill":145,"stroke":145,"style":146},[80,186,187],{"x":112,"y":176,"fill":77,"style":133,"textAnchor":105},"no",[57,189],{"x":116,"y":173,"width":101,"height":89,"rx":61,"fill":145,"stroke":145,"style":146},[80,191,192],{"x":119,"y":176,"fill":77,"style":133,"textAnchor":105},"native",[57,194],{"x":82,"y":195,"width":88,"height":89,"rx":61,"fill":76,"stroke":77,"style":124},"176.0",[80,197,199],{"x":93,"y":198,"fill":77,"style":95,"textAnchor":96},"195.5","JS-injected link",[57,201],{"x":100,"y":195,"width":101,"height":89,"rx":61,"fill":77,"stroke":77,"style":90},[80,203,204],{"x":104,"y":198,"fill":77,"style":133,"textAnchor":105},"varies",[57,206],{"x":109,"y":195,"width":101,"height":89,"rx":61,"fill":137,"stroke":138,"style":139},[80,208,166],{"x":112,"y":198,"fill":77,"style":133,"textAnchor":105},[57,210],{"x":116,"y":195,"width":101,"height":89,"rx":61,"fill":137,"stroke":138,"style":139},[80,212,76],{"x":119,"y":198,"fill":77,"style":133,"textAnchor":105},[214,215,217],"h2",{"id":216},"rapid-diagnosis","Rapid Diagnosis",[219,220,221,229,235,241],"ul",{},[222,223,224,228],"li",{},[225,226,227],"strong",{},"Check stylesheet links"," in the head: any without a non-matching media query and without an async pattern are blocking.",[222,230,231,234],{},[225,232,233],{},"Watch the filmstrip"," in a lab run: unstyled content followed by a styled frame indicates async CSS that should be critical.",[222,236,237,240],{},[225,238,239],{},"Check CLS attribution"," for shifts that coincide with a stylesheet finishing.",[222,242,243,246],{},[225,244,245],{},"Check stylesheet priority"," in the Network panel; very-low-priority CSS may arrive late on congested connections.",[214,248,250],{"id":249},"root-cause-analysis","Root Cause Analysis",[15,252,253,256],{},[225,254,255],{},"1. No native async for CSS."," All patterns are workarounds with trade-offs.",[15,258,259,262],{},[225,260,261],{},"2. Incomplete critical CSS."," Async CSS that styles above-the-fold content causes FOUC.",[15,264,265,268],{},[225,266,267],{},"3. Low priority."," The media swap uses print priority, so the stylesheet can be delayed behind images.",[15,270,271,274,275,278],{},[225,272,273],{},"4. JavaScript dependency."," Most patterns rely on an ",[30,276,277],{},"onload"," handler to apply the stylesheet.",[214,280,282],{"id":281},"step-by-step-resolution","Step-by-Step Resolution",[284,285,287],"h3",{"id":286},"_1-use-the-media-swap-for-most-cases","1. Use the media swap for most cases",[289,290,295],"pre",{"className":291,"code":292,"language":293,"meta":294,"style":294},"language-html shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u003Clink rel=\"stylesheet\" href=\"\u002Fcss\u002Fsite.4f2a1c.css\" media=\"print\" onload=\"this.media='all'; this.onload=null\">\n\u003Cnoscript>\u003Clink rel=\"stylesheet\" href=\"\u002Fcss\u002Fsite.4f2a1c.css\">\u003C\u002Fnoscript>\n\u003C!-- trade-off: print-media stylesheets get the lowest fetch priority, so on busy\n     pages the full CSS may arrive after images; add a preload if it is needed soon. -->\n","html","",[30,296,297,375,407,414],{"__ignoreMap":294},[298,299,302,306,310,314,317,321,324,326,329,332,334,337,340,342,345,348,351,353,356,359,361,363,365,367,370,372],"span",{"class":300,"line":301},"line",1,[298,303,305],{"class":304},"saISM","\u003C",[298,307,309],{"class":308},"sZBmE","link",[298,311,313],{"class":312},"sPXB4"," rel",[298,315,316],{"class":304},"=",[298,318,320],{"class":319},"sZ8jY","\"stylesheet\"",[298,322,323],{"class":312}," href",[298,325,316],{"class":304},[298,327,328],{"class":319},"\"\u002Fcss\u002Fsite.4f2a1c.css\"",[298,330,331],{"class":312}," media",[298,333,316],{"class":304},[298,335,336],{"class":319},"\"print\"",[298,338,339],{"class":312}," onload",[298,341,316],{"class":304},[298,343,344],{"class":319},"\"",[298,346,347],{"class":312},"this",[298,349,350],{"class":319},".",[298,352,36],{"class":304},[298,354,316],{"class":355},"sPARh",[298,357,358],{"class":319},"'all'; ",[298,360,347],{"class":312},[298,362,350],{"class":319},[298,364,277],{"class":304},[298,366,316],{"class":355},[298,368,369],{"class":312},"null",[298,371,344],{"class":319},[298,373,374],{"class":304},">\n",[298,376,378,380,383,386,388,390,392,394,396,398,400,403,405],{"class":300,"line":377},2,[298,379,305],{"class":304},[298,381,382],{"class":308},"noscript",[298,384,385],{"class":304},">\u003C",[298,387,309],{"class":308},[298,389,313],{"class":312},[298,391,316],{"class":304},[298,393,320],{"class":319},[298,395,323],{"class":312},[298,397,316],{"class":304},[298,399,328],{"class":319},[298,401,402],{"class":304},">\u003C\u002F",[298,404,382],{"class":308},[298,406,374],{"class":304},[298,408,410],{"class":300,"line":409},3,[298,411,413],{"class":412},"sjfSM","\u003C!-- trade-off: print-media stylesheets get the lowest fetch priority, so on busy\n",[298,415,417],{"class":300,"line":416},4,[298,418,419],{"class":412},"     pages the full CSS may arrive after images; add a preload if it is needed soon. -->\n",[284,421,423],{"id":422},"_2-use-preload-when-the-stylesheet-is-needed-quickly","2. Use preload when the stylesheet is needed quickly",[289,425,427],{"className":291,"code":426,"language":293,"meta":294,"style":294},"\u003Clink rel=\"preload\" href=\"\u002Fcss\u002Fsite.4f2a1c.css\" as=\"style\" onload=\"this.onload=null; this.rel='stylesheet'\">\n\u003Cnoscript>\u003Clink rel=\"stylesheet\" href=\"\u002Fcss\u002Fsite.4f2a1c.css\">\u003C\u002Fnoscript>\n\u003C!-- trade-off: high priority competes with the LCP image for bandwidth; use it for\n     stylesheets that style content seen within the first scroll. -->\n",[30,428,429,488,516,521],{"__ignoreMap":294},[298,430,431,433,435,437,439,442,444,446,448,451,453,456,458,460,462,464,466,468,470,472,475,477,479,481,483,486],{"class":300,"line":301},[298,432,305],{"class":304},[298,434,309],{"class":308},[298,436,313],{"class":312},[298,438,316],{"class":304},[298,440,441],{"class":319},"\"preload\"",[298,443,323],{"class":312},[298,445,316],{"class":304},[298,447,328],{"class":319},[298,449,450],{"class":312}," as",[298,452,316],{"class":304},[298,454,455],{"class":319},"\"style\"",[298,457,339],{"class":312},[298,459,316],{"class":304},[298,461,344],{"class":319},[298,463,347],{"class":312},[298,465,350],{"class":319},[298,467,277],{"class":304},[298,469,316],{"class":355},[298,471,369],{"class":312},[298,473,474],{"class":319},"; ",[298,476,347],{"class":312},[298,478,350],{"class":319},[298,480,40],{"class":304},[298,482,316],{"class":355},[298,484,485],{"class":319},"'stylesheet'\"",[298,487,374],{"class":304},[298,489,490,492,494,496,498,500,502,504,506,508,510,512,514],{"class":300,"line":377},[298,491,305],{"class":304},[298,493,382],{"class":308},[298,495,385],{"class":304},[298,497,309],{"class":308},[298,499,313],{"class":312},[298,501,316],{"class":304},[298,503,320],{"class":319},[298,505,323],{"class":312},[298,507,316],{"class":304},[298,509,328],{"class":319},[298,511,402],{"class":304},[298,513,382],{"class":308},[298,515,374],{"class":304},[298,517,518],{"class":300,"line":409},[298,519,520],{"class":412},"\u003C!-- trade-off: high priority competes with the LCP image for bandwidth; use it for\n",[298,522,523],{"class":300,"line":416},[298,524,525],{"class":412},"     stylesheets that style content seen within the first scroll. -->\n",[284,527,529],{"id":528},"_3-split-by-media-query-where-possible","3. Split by media query where possible",[289,531,533],{"className":291,"code":532,"language":293,"meta":294,"style":294},"\u003Clink rel=\"stylesheet\" href=\"\u002Fcss\u002Fbase.css\">\n\u003Clink rel=\"stylesheet\" href=\"\u002Fcss\u002Fdesktop.css\" media=\"(min-width: 1024px)\">\n\u003Clink rel=\"stylesheet\" href=\"\u002Fcss\u002Fprint.css\" media=\"print\">\n",[30,534,535,556,584],{"__ignoreMap":294},[298,536,537,539,541,543,545,547,549,551,554],{"class":300,"line":301},[298,538,305],{"class":304},[298,540,309],{"class":308},[298,542,313],{"class":312},[298,544,316],{"class":304},[298,546,320],{"class":319},[298,548,323],{"class":312},[298,550,316],{"class":304},[298,552,553],{"class":319},"\"\u002Fcss\u002Fbase.css\"",[298,555,374],{"class":304},[298,557,558,560,562,564,566,568,570,572,575,577,579,582],{"class":300,"line":377},[298,559,305],{"class":304},[298,561,309],{"class":308},[298,563,313],{"class":312},[298,565,316],{"class":304},[298,567,320],{"class":319},[298,569,323],{"class":312},[298,571,316],{"class":304},[298,573,574],{"class":319},"\"\u002Fcss\u002Fdesktop.css\"",[298,576,331],{"class":312},[298,578,316],{"class":304},[298,580,581],{"class":319},"\"(min-width: 1024px)\"",[298,583,374],{"class":304},[298,585,586,588,590,592,594,596,598,600,603,605,607,609],{"class":300,"line":409},[298,587,305],{"class":304},[298,589,309],{"class":308},[298,591,313],{"class":312},[298,593,316],{"class":304},[298,595,320],{"class":319},[298,597,323],{"class":312},[298,599,316],{"class":304},[298,601,602],{"class":319},"\"\u002Fcss\u002Fprint.css\"",[298,604,331],{"class":312},[298,606,316],{"class":304},[298,608,336],{"class":319},[298,610,374],{"class":304},[15,612,613],{},"Non-matching stylesheets are downloaded at low priority without blocking. No JavaScript is needed.",[284,615,617],{"id":616},"_4-defer-component-css-until-it-is-needed","4. Defer component CSS until it is needed",[15,619,620],{},"Styles for modals, carousels further down the page, or account menus can be loaded when the component is first used (code-split CSS in modern bundlers does this automatically for lazily loaded components).",[15,622,623],{},[48,624,55,627,55,630,55,633,55,635,55,638,55,640,55,649,55,653,55,660,55,666,55,670,55,675,55,679,55,683,55,687,55,692,55,697,55,702,55,708,55,712,55,716,55,719,55,723,55,726,55,730,55,734,55,738,55],{"viewBox":625,"width":51,"role":52,"ariaLabel":626,"style":54},"0 0 760 264","Timeline showing how a preloaded stylesheet competes with the LCP image while a media-swapped one downloads after it.",[57,628],{"className":629,"x":61,"y":61,"width":51,"height":51,"fill":62},[60],[64,631,632],{},"Async CSS priority vs LCP image on a slow connection",[68,634,626],{},[57,636],{"x":72,"y":72,"width":73,"height":637,"rx":75,"fill":76,"stroke":77,"style":78},"262",[80,639,632],{"x":82,"y":83,"fill":77,"style":84},[300,641],{"x1":642,"y1":643,"x2":642,"y2":644,"stroke":138,"strokeWidth":645,"strokeDashArray":646,"style":648},"471.7","72.0","220.0","1.5",[647,647],"4","stroke-opacity:0.9",[80,650,652],{"x":82,"y":651,"fill":77,"style":95},"96.0","preload swap",[57,654],{"x":655,"y":656,"width":657,"height":658,"rx":659,"fill":145,"stroke":145,"style":146},"266.5","78.0","192.3","26.0","3",[80,661,665],{"x":662,"y":663,"fill":77,"style":664,"textAnchor":105},"362.7","95.5","font-size:11.5px","site.css (high)",[57,667],{"x":655,"y":668,"width":669,"height":658,"rx":659,"fill":76,"stroke":77,"style":124},"110.0","313.4",[80,671,674],{"x":672,"y":673,"fill":77,"style":664,"textAnchor":105},"423.2","127.5","LCP image shares bandwidth",[80,676,678],{"x":82,"y":677,"fill":77,"style":95},"166.0","media=print swap",[57,680],{"x":655,"y":681,"width":682,"height":658,"rx":659,"fill":137,"stroke":138,"style":139},"148.0","204.4",[80,684,686],{"x":685,"y":176,"fill":77,"style":664,"textAnchor":105},"368.7","LCP image",[57,688],{"x":689,"y":690,"width":691,"height":658,"rx":659,"fill":77,"stroke":77,"style":90},"363.4","180.0","289.2",[80,693,696],{"x":694,"y":695,"fill":77,"style":664,"textAnchor":105},"508.0","197.5","site.css (lowest)",[300,698],{"x1":699,"y1":644,"x2":700,"y2":644,"stroke":77,"style":701},"144.7","726.0","stroke-opacity:0.4",[80,703,707],{"x":704,"y":705,"fill":706,"style":664,"textAnchor":105},"155.4","237.0","#51617a","0ms",[80,709,711],{"x":710,"y":705,"fill":706,"style":664,"textAnchor":105},"217.3","300ms",[80,713,715],{"x":714,"y":705,"fill":706,"style":664,"textAnchor":105},"290.0","600ms",[80,717,718],{"x":662,"y":705,"fill":706,"style":664,"textAnchor":105},"900ms",[80,720,722],{"x":721,"y":705,"fill":706,"style":664,"textAnchor":105},"435.3","1200ms",[80,724,725],{"x":694,"y":705,"fill":706,"style":664,"textAnchor":105},"1500ms",[80,727,729],{"x":728,"y":705,"fill":706,"style":664,"textAnchor":105},"580.7","1800ms",[80,731,733],{"x":732,"y":705,"fill":706,"style":664,"textAnchor":105},"653.3","2100ms",[80,735,737],{"x":736,"y":705,"fill":706,"style":664,"textAnchor":105},"712.3","2400ms",[80,739,743],{"x":642,"y":740,"fill":741,"style":742,"textAnchor":105},"68.0","#8a6608","font-size:12px;font-weight:700","LCP",[214,745,747],{"id":746},"verification","Verification",[15,749,750],{},"In the Network panel, the full stylesheet should not be marked render-blocking, and should load at the expected priority. FCP should occur before the stylesheet finishes. Watch the filmstrip and CLS: no unstyled frames, no shifts when the stylesheet applies. Test with JavaScript disabled to confirm the noscript fallback works.",[214,752,754],{"id":753},"worked-example-a-marketing-site","Worked Example: A Marketing Site",[15,756,757,758,761],{},"A marketing site switched its 90KB stylesheet to ",[30,759,760],{},"rel=preload"," with an onload swap after inlining 8KB of critical CSS. FCP improved by 700ms, but LCP improved by only 150ms: the high-priority stylesheet competed with the hero image. Switching to the media swap (lowest priority) improved LCP by a further 280ms, because the hero image now had the bandwidth to itself, while the full stylesheet still arrived before users scrolled. A CLS check confirmed no shifts, since all above-the-fold rules were in the critical block.",[15,763,764],{},[48,765,55,768,55,771,55,774,55,776,55,793,55,796,55,798,55,803,55,808,55,811,55,816,55,823,55,828,55,832,55,836,55,839,55,843,55,845,55,848,55,851,55,854,55,857,55,860,55,863,55,866,55,868,55,871,55,874,55,877,55,881,55,884,55,887,55],{"viewBox":766,"width":51,"role":52,"ariaLabel":767,"style":54},"0 0 760 325","Decision sequence for picking how to load a stylesheet without blocking the first paint.",[57,769],{"className":770,"x":61,"y":61,"width":51,"height":51,"fill":62},[60],[64,772,773],{},"Choosing an async CSS pattern",[68,775,767],{},[777,778,779],"defs",{},[780,781,788],"marker",{"id":782,"viewBox":783,"refX":784,"refY":785,"markerWidth":786,"markerHeight":786,"orient":787},"fa076b9f14","0 0 10 10","9","5","7","auto-start-reverse",[789,790],"path",{"d":791,"fill":77,"style":792},"M0 0 L10 5 L0 10 z","fill-opacity:0.7",[57,794],{"x":72,"y":72,"width":73,"height":795,"rx":75,"fill":76,"stroke":77,"style":78},"323",[80,797,773],{"x":82,"y":83,"fill":77,"style":84},[57,799],{"x":82,"y":87,"width":800,"height":801,"rx":802,"fill":77,"stroke":77,"style":90},"320.0","35.0","6",[80,804,807],{"x":805,"y":656,"fill":77,"style":806,"textAnchor":105},"188.0","font-size:13px;font-weight:700","Does the CSS style above-the-fold content?",[57,809],{"x":810,"y":87,"width":800,"height":801,"rx":802,"fill":76,"stroke":77,"style":124},"412.0",[80,812,815],{"x":813,"y":656,"fill":77,"style":814,"textAnchor":105},"572.0","font-size:12.5px","Inline it as critical CSS instead",[300,817],{"x1":818,"y1":819,"x2":820,"y2":819,"stroke":77,"strokeWidth":645,"style":821,"markerEnd":822},"348.0","73.5","410.0","stroke-opacity:0.6","url(#fa076b9f14)",[80,824,166],{"x":825,"y":826,"fill":145,"style":827,"textAnchor":105},"380.0","66.5","font-size:11.5px;font-weight:700",[300,829],{"x1":805,"y1":830,"x2":805,"y2":831,"stroke":77,"strokeWidth":645,"style":821,"markerEnd":822},"91.0","125.0",[80,833,187],{"x":834,"y":835,"fill":706,"style":827},"196.0","113.0",[57,837],{"x":82,"y":838,"width":800,"height":801,"rx":802,"fill":77,"stroke":77,"style":90},"127.0",[80,840,842],{"x":805,"y":841,"fill":77,"style":806,"textAnchor":105},"149.0","Is it needed within the first scroll?",[57,844],{"x":810,"y":838,"width":800,"height":801,"rx":802,"fill":145,"stroke":145,"style":146},[80,846,847],{"x":813,"y":841,"fill":77,"style":814,"textAnchor":105},"Preload with onload rel swap",[300,849],{"x1":818,"y1":850,"x2":820,"y2":850,"stroke":77,"strokeWidth":645,"style":821,"markerEnd":822},"144.5",[80,852,166],{"x":825,"y":853,"fill":145,"style":827,"textAnchor":105},"137.5",[300,855],{"x1":805,"y1":856,"x2":805,"y2":834,"stroke":77,"strokeWidth":645,"style":821,"markerEnd":822},"162.0",[80,858,187],{"x":834,"y":859,"fill":706,"style":827},"184.0",[57,861],{"x":82,"y":862,"width":800,"height":801,"rx":802,"fill":77,"stroke":77,"style":90},"198.0",[80,864,865],{"x":805,"y":644,"fill":77,"style":806,"textAnchor":105},"Does it apply only at some breakpoints?",[57,867],{"x":810,"y":862,"width":800,"height":801,"rx":802,"fill":145,"stroke":145,"style":146},[80,869,870],{"x":813,"y":644,"fill":77,"style":814,"textAnchor":105},"Split it into media-query stylesheets",[300,872],{"x1":818,"y1":873,"x2":820,"y2":873,"stroke":77,"strokeWidth":645,"style":821,"markerEnd":822},"215.5",[80,875,166],{"x":825,"y":876,"fill":145,"style":827,"textAnchor":105},"208.5",[300,878],{"x1":805,"y1":879,"x2":805,"y2":880,"stroke":77,"strokeWidth":645,"style":821,"markerEnd":822},"233.0","267.0",[80,882,187],{"x":834,"y":883,"fill":706,"style":827},"255.0",[57,885],{"x":82,"y":886,"width":800,"height":83,"rx":802,"fill":137,"stroke":138,"style":139},"269.0",[80,888,890],{"x":805,"y":889,"fill":77,"style":814,"textAnchor":105},"290.5","Media swap (print to all) with a noscript fallback",[214,892,894],{"id":893},"when-not-to-load-css-asynchronously","When Not to Load CSS Asynchronously",[15,896,897],{},"Async loading is a pairing: it only works with complete critical CSS. If you cannot generate reliable critical CSS — for example, highly dynamic pages where above-the-fold content varies widely — a single small, cached, same-origin, render-blocking stylesheet may be the better choice. A 25KB compressed stylesheet on the same HTTP\u002F2 connection as the HTML often costs only a round trip, and avoids FOUC risk entirely. Measure: if the gap between TTFB and FCP is already small, the async complexity is not worth it.",[214,899,901],{"id":900},"a-csp-friendly-loader","A CSP-Friendly Loader",[15,903,904,905,907],{},"Inline ",[30,906,277],{}," attributes conflict with a strict Content Security Policy. A tiny external script avoids them and handles every deferred stylesheet consistently:",[289,909,913],{"className":910,"code":911,"language":912,"meta":294,"style":294},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F \u002Fjs\u002Fasync-css.js, loaded with defer.\nfor (const link of document.querySelectorAll('link[data-async-css]')) {\n  const apply = () => { link.media = link.dataset.media || 'all'; };\n  if (link.sheet) apply(); else link.addEventListener('load', apply, { once: true });\n}\n\u002F\u002F trade-off: a deferred script runs after parsing, so the swap happens slightly\n\u002F\u002F later than an inline onload; the stylesheet itself still downloads early.\n","javascript",[30,914,915,920,953,987,1024,1030,1036],{"__ignoreMap":294},[298,916,917],{"class":300,"line":301},[298,918,919],{"class":412},"\u002F\u002F \u002Fjs\u002Fasync-css.js, loaded with defer.\n",[298,921,922,925,928,931,934,937,940,944,947,950],{"class":300,"line":377},[298,923,924],{"class":355},"for",[298,926,927],{"class":304}," (",[298,929,930],{"class":355},"const",[298,932,933],{"class":312}," link",[298,935,936],{"class":355}," of",[298,938,939],{"class":304}," document.",[298,941,943],{"class":942},"smZ65","querySelectorAll",[298,945,946],{"class":304},"(",[298,948,949],{"class":319},"'link[data-async-css]'",[298,951,952],{"class":304},")) {\n",[298,954,955,958,961,964,967,970,973,975,978,981,984],{"class":300,"line":409},[298,956,957],{"class":355},"  const",[298,959,960],{"class":942}," apply",[298,962,963],{"class":355}," =",[298,965,966],{"class":304}," () ",[298,968,969],{"class":355},"=>",[298,971,972],{"class":304}," { link.media ",[298,974,316],{"class":355},[298,976,977],{"class":304}," link.dataset.media ",[298,979,980],{"class":355},"||",[298,982,983],{"class":319}," 'all'",[298,985,986],{"class":304},"; };\n",[298,988,989,992,995,998,1001,1004,1007,1010,1012,1015,1018,1021],{"class":300,"line":416},[298,990,991],{"class":355},"  if",[298,993,994],{"class":304}," (link.sheet) ",[298,996,997],{"class":942},"apply",[298,999,1000],{"class":304},"(); ",[298,1002,1003],{"class":355},"else",[298,1005,1006],{"class":304}," link.",[298,1008,1009],{"class":942},"addEventListener",[298,1011,946],{"class":304},[298,1013,1014],{"class":319},"'load'",[298,1016,1017],{"class":304},", apply, { once: ",[298,1019,1020],{"class":312},"true",[298,1022,1023],{"class":304}," });\n",[298,1025,1027],{"class":300,"line":1026},5,[298,1028,1029],{"class":304},"}\n",[298,1031,1033],{"class":300,"line":1032},6,[298,1034,1035],{"class":412},"\u002F\u002F trade-off: a deferred script runs after parsing, so the swap happens slightly\n",[298,1037,1039],{"class":300,"line":1038},7,[298,1040,1041],{"class":412},"\u002F\u002F later than an inline onload; the stylesheet itself still downloads early.\n",[15,1043,1044,1045,1048,1049,1052],{},"Mark stylesheets with ",[30,1046,1047],{},"media=\"print\" data-async-css"," in the HTML. Because the check for ",[30,1050,1051],{},"link.sheet"," handles stylesheets that finished before the script ran, no load event is missed.",[214,1054,1056],{"id":1055},"measuring-whether-async-loading-paid-off","Measuring Whether Async Loading Paid Off",[15,1058,1059,1060,1063],{},"Compare three timings before and after the change, on the same throttled profile: FCP, LCP and the moment the full stylesheet finishes (from Resource Timing). FCP should move earlier by roughly the stylesheet's former download time. LCP should move earlier too, unless the LCP image was the bottleneck — in which case check that the stylesheet is not now competing with it. The stylesheet's own finish time matters for users who interact quickly: if it arrives after a typical first click, interactive elements styled only by the full CSS may look broken briefly. RUM can capture this by logging the stylesheet's ",[30,1061,1062],{},"responseEnd"," alongside the first interaction time.",[214,1065,1067],{"id":1066},"common-mistakes","Common Mistakes",[219,1069,1070,1076,1085,1091],{},[222,1071,1072,1075],{},[225,1073,1074],{},"Forgetting the noscript fallback."," Pages without JavaScript remain unstyled.",[222,1077,1078,1084],{},[225,1079,1080,1081,1083],{},"Leaving ",[30,1082,277],{}," active."," Some browsers re-fire load when media changes; clear the handler.",[222,1086,1087,1090],{},[225,1088,1089],{},"Async-loading CSS for visible content."," FOUC and CLS.",[222,1092,1093,1096],{},[225,1094,1095],{},"Preloading every stylesheet."," Turns them all into high-priority downloads competing with the LCP image.",[214,1098,1100],{"id":1099},"edge-cases","Edge Cases",[15,1102,1103,1106,1107,1109,1110,1113,1114,1117],{},[225,1104,1105],{},"Content Security Policy."," Inline ",[30,1108,277],{}," handlers require ",[30,1111,1112],{},"'unsafe-inline'"," or hashes; use a small external script that swaps media for all ",[30,1115,1116],{},"link[data-async]"," elements instead.",[15,1119,1120,1123],{},[225,1121,1122],{},"Print styles."," If you use the media swap on the main stylesheet, print a page to confirm print styles still apply as intended.",[15,1125,1126,1129],{},[225,1127,1128],{},"Back-forward cache."," Restored pages keep their applied stylesheets; no special handling needed.",[15,1131,1132,1135],{},[225,1133,1134],{},"SPAs."," Bundlers inject CSS for lazy routes asynchronously; ensure route CSS loads before the route renders to avoid FOUC on navigation.",[214,1137,1139],{"id":1138},"faq","FAQ",[1141,1142,1145,1149],"details",{"className":1143},[1144],"faq-item",[1146,1147,1148],"summary",{},"Why use media=\"print\" to load CSS asynchronously?",[15,1150,1151,1152,1155],{},"Stylesheets for non-matching media are downloaded without blocking rendering. Switching the media to ",[30,1153,1154],{},"all"," once loaded applies the styles.",[1141,1157,1159,1162],{"className":1158},[1144],[1146,1160,1161],{},"Is the preload pattern better than the media swap?",[15,1163,1164],{},"Preload gives higher priority, so the stylesheet arrives sooner, but it competes with critical resources such as the LCP image. Choose based on how soon the CSS is needed.",[1141,1166,1168,1171],{"className":1167},[1144],[1146,1169,1170],{},"Is loadCSS still needed?",[15,1172,1173],{},"The loadCSS library popularised these patterns. Modern browsers support preload and onload on link elements natively, so a library is generally unnecessary.",[1141,1175,1177,1180],{"className":1176},[1144],[1146,1178,1179],{},"Can I make CSS async without JavaScript?",[15,1181,1182],{},"Only by splitting stylesheets by media query, which loads non-matching sheets without blocking. Full async application of styles needs a small amount of JavaScript.",[1141,1184,1186,1189],{"className":1185},[1144],[1146,1187,1188],{},"Will async CSS hurt CLS?",[15,1190,1191],{},"Only if it styles content already visible. With complete critical CSS, async loading should not cause shifts.",[1141,1193,1195,1198],{"className":1194},[1144],[1146,1196,1197],{},"Does async CSS help INP?",[15,1199,1200],{},"Indirectly at most. Parsing a large stylesheet after load can cause a long task that coincides with early interactions; smaller CSS helps more than loading strategy.",[214,1202,1204],{"id":1203},"related","Related",[219,1206,1207,1214,1221],{},[222,1208,1209,1213],{},[19,1210,1212],{"href":1211},"\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fextracting-critical-css-at-build-time\u002F","Extracting critical CSS at build time"," — the prerequisite for safe async CSS.",[222,1215,1216,1220],{},[19,1217,1219],{"href":1218},"\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fremoving-unused-css-with-purgecss\u002F","Removing unused CSS with PurgeCSS"," — make the async stylesheet smaller.",[222,1222,1223,1227],{},[19,1224,1226],{"href":1225},"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Fusing-fetchpriority-to-prioritize-the-lcp-image\u002F","Using fetchpriority to prioritize the LCP image"," — avoid CSS competing with the hero.",[1229,1230,1232],"script",{"type":1231},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Load Non-Critical CSS Asynchronously\",\n  \"description\": \"The reliable patterns for loading CSS without blocking rendering, how they differ, and how to avoid unstyled flashes and layout shifts.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Use the media swap for most cases\",\n      \"text\": \"Use the media swap for most cases\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Use preload when the stylesheet is needed quickly\",\n      \"text\": \"Use preload when the stylesheet is needed quickly\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Split by media query where possible\",\n      \"text\": \"Non-matching stylesheets are downloaded at low priority without blocking.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Defer component CSS until it is needed\",\n      \"text\": \"Styles for modals, carousels further down the page, or account menus can be loaded when the component is first used (code-split CSS in modern bundlers does this automatically for lazily loaded components).\"\n    }\n  ]\n}\n",[1229,1234,1235],{"type":1231},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Load Non-Critical CSS Asynchronously\",\n  \"description\": \"The reliable patterns for loading CSS without blocking rendering, how they differ, and how to avoid unstyled flashes and layout shifts.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Floading-non-critical-css-asynchronously\u002F\"\n  }\n}\n",[1229,1237,1238],{"type":1231},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"Rendering & CSS Performance\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Frendering-css-performance\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Critical CSS & Render-Blocking Resources\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Loading Non-Critical CSS Asynchronously\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Floading-non-critical-css-asynchronously\u002F\"\n    }\n  ]\n}\n",[1240,1241,1242],"style",{},"html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sZBmE, html code.shiki .sZBmE{--shiki-default:#024C1A;--shiki-dark:#72F088;--shiki-light:#024C1A}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}",{"title":294,"searchDepth":377,"depth":377,"links":1244},[1245,1246,1247,1253,1254,1255,1256,1257,1258,1259,1260,1261],{"id":216,"depth":377,"text":217},{"id":249,"depth":377,"text":250},{"id":281,"depth":377,"text":282,"children":1248},[1249,1250,1251,1252],{"id":286,"depth":409,"text":287},{"id":422,"depth":409,"text":423},{"id":528,"depth":409,"text":529},{"id":616,"depth":409,"text":617},{"id":746,"depth":377,"text":747},{"id":753,"depth":377,"text":754},{"id":893,"depth":377,"text":894},{"id":900,"depth":377,"text":901},{"id":1055,"depth":377,"text":1056},{"id":1066,"depth":377,"text":1067},{"id":1099,"depth":377,"text":1100},{"id":1138,"depth":377,"text":1139},{"id":1203,"depth":377,"text":1204},"The reliable patterns for loading CSS without blocking rendering, how they differ, and how to avoid unstyled flashes and layout shifts.","md",{"slug":1265,"type":1266,"breadcrumb":1267,"datePublished":1275,"dateModified":1275},"loading-non-critical-css-asynchronously","article",[1268,1271,1272,1273],{"name":1269,"url":1270},"Home","\u002F",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1274},"\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Floading-non-critical-css-asynchronously\u002F","2026-10-06",true,"\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Floading-non-critical-css-asynchronously",{"title":1279,"description":1280},"Loading Non-Critical CSS Asynchronously Without FOUC","Load stylesheets without blocking first paint using the media swap, rel=preload, or split media queries — without flashes of unstyled content or layout shifts.","rendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Floading-non-critical-css-asynchronously\u002Findex","aHmcq8qJjy_xep3I_K5PLY_B1M5WiILoABytAJY7XjE",[1284,1288],{"title":1285,"path":1286,"stem":1287},"Extracting Critical CSS at Build Time","\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fextracting-critical-css-at-build-time","rendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fextracting-critical-css-at-build-time\u002Findex",{"title":1289,"path":1290,"stem":1291},"Removing Unused CSS with PurgeCSS","\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fremoving-unused-css-with-purgecss","rendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fremoving-unused-css-with-purgecss\u002Findex",1791308079972]