[{"data":1,"prerenderedAt":1055},["ShallowReactive",2],{"content:\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render":3,"surroundings:\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render":1046},{"id":4,"title":5,"body":6,"description":1027,"extension":1028,"meta":1029,"navigation":1040,"path":1041,"seo":1042,"stem":1044,"__hash__":1045},"content\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render\u002Findex.md","Preloading Google Fonts Without Blocking Render",{"type":7,"value":8,"toc":1019},"minimark",[9,13,33,38,93,248,252,266,280,286,292,296,313,400,407,417,539,546,555,618,625,638,769,772,776,779,782,785,885,888,892,904,929,942,955,970,979,983,1004,1009,1012,1015],[10,11,5],"h1",{"id":12},"preloading-google-fonts-without-blocking-render",[14,15,16,17,22,23,27,28,32],"p",{},"This guide extends ",[18,19,21],"a",{"href":20},"\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002F","Font Loading & Text Rendering Performance"," within ",[18,24,26],{"href":25},"\u002Fcore-web-vitals-measurement\u002F","Core Web Vitals & Measurement"," to the most common integration on the web — and one of the most reliably misconfigured. The default Google Fonts snippet puts a render-blocking stylesheet on a third-party origin in front of a font file on a ",[29,30,31],"em",{},"second"," third-party origin, which is two connections and two round trips before a glyph exists.",[34,35,37],"h2",{"id":36},"rapid-diagnosis-find-the-second-hop","Rapid Diagnosis: Find the Second Hop",[39,40,41,58,72,82],"ul",{},[42,43,44,48,49,53,54,57],"li",{},[45,46,47],"strong",{},"Look for two origins."," In the Network panel, filter by domain. The stylesheet comes from ",[50,51,52],"code",{},"fonts.googleapis.com","; the font files come from ",[50,55,56],{},"fonts.gstatic.com",". Two DNS lookups, two TLS handshakes.",[42,59,60,63,64,67,68,71],{},[45,61,62],{},"Check the initiator chain."," Click the ",[50,65,66],{},".woff2"," request and read ",[45,69,70],{},"Initiator",". It will point at the CSS file, not at your document — that is the serialisation you are trying to break.",[42,73,74,77,78,81],{},[45,75,76],{},"Read the render-blocking status."," The stylesheet is render-blocking by default, so First Contentful Paint cannot happen until it returns. On a slow connection that alone can cost ",[50,79,80],{},"300–600ms",".",[42,83,84,87,88,92],{},[45,85,86],{},"Confirm the font is on the LCP path."," If your LCP element is text, the font's arrival gates it. Check with the ",[18,89,91],{"href":90},"\u002Fcore-web-vitals-measurement\u002Fmeasuring-lcp-with-chrome-devtools\u002F","LCP measurement workflow"," whether render delay dominates the phase breakdown.",[94,95,102,103,110,111,110,115,110,119,110,128,110,135,110,140,110,148,110,155,110,162,110,167,110,173,110,177,110,181,110,184,110,188,110,192,110,196,110,199,110,205,110,210,110,215,110,219,110,222,110,226,110,228,110,231,110,235,110,239,110,244,110],"svg",{"xmlns":96,"viewBox":97,"width":98,"role":99,"ariaLabel":100,"style":101},"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","0 0 760 236","100%","img","Comparison of the default Google Fonts chain requiring two third-party connections in series against an optimised chain where preconnect warms both origins and the font is preloaded directly","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)","\n  ",[104,105],"rect",{"className":106,"x":108,"y":108,"width":98,"height":98,"fill":109},[107],"svg-canvas","0","#ffffff"," ",[112,113,114],"title",{},"The Google Fonts request chain, default and optimised",[116,117,118],"desc",{},"The default path connects to googleapis, downloads CSS, then connects to gstatic and downloads the font. The optimised path warms both origins in parallel and starts the font download directly from the document.",[104,120],{"x":121,"y":121,"width":122,"height":123,"rx":124,"fill":125,"stroke":126,"style":127},"1","758","234","10","none","currentColor","stroke-opacity:0.18",[129,130,134],"text",{"x":131,"y":132,"fill":126,"style":133},"24","32","font-size:16px;font-weight:700","Two origins, in series or in parallel",[129,136,139],{"x":131,"y":137,"fill":126,"style":138},"70","font-size:11.5px;font-weight:700","Default",[104,141],{"x":142,"y":143,"width":144,"height":145,"rx":146,"fill":126,"stroke":126,"style":147},"110","54","140","30","5","fill-opacity:0.05;stroke-opacity:0.3",[129,149,154],{"x":150,"y":151,"fill":126,"style":152,"textAnchor":153},"180","74","font-size:11px;","middle","connect googleapis",[156,157],"line",{"x1":158,"y1":159,"x2":160,"y2":159,"stroke":126,"style":161},"250","69","268","stroke-opacity:0.4",[163,164],"polygon",{"points":165,"fill":126,"style":166},"276,69 266,64 266,74","fill-opacity:0.55",[104,168],{"x":169,"y":143,"width":170,"height":145,"rx":146,"fill":171,"stroke":171,"style":172},"276","120","#0466c8","fill-opacity:0.16;stroke-opacity:0.5",[129,174,176],{"x":175,"y":151,"fill":126,"style":152,"textAnchor":153},"336","CSS (blocking)",[156,178],{"x1":179,"y1":159,"x2":180,"y2":159,"stroke":126,"style":161},"396","414",[163,182],{"points":183,"fill":126,"style":166},"422,69 412,64 412,74",[104,185],{"x":186,"y":143,"width":187,"height":145,"rx":146,"fill":126,"stroke":126,"style":147},"422","130",[129,189,191],{"x":190,"y":151,"fill":126,"style":152,"textAnchor":153},"487","connect gstatic",[156,193],{"x1":194,"y1":159,"x2":195,"y2":159,"stroke":126,"style":161},"552","570",[163,197],{"points":198,"fill":126,"style":166},"578,69 568,64 568,74",[104,200],{"x":201,"y":143,"width":170,"height":145,"rx":146,"fill":202,"stroke":203,"style":204},"578","#ffc300","#b8860b","fill-opacity:0.28",[129,206,209],{"x":207,"y":151,"fill":126,"style":208,"textAnchor":153},"638","font-size:11px;font-weight:700;","font file",[156,211],{"x1":131,"y1":212,"x2":213,"y2":212,"stroke":126,"style":214},"112","736","stroke-opacity:0.2",[129,216,218],{"x":131,"y":217,"fill":126,"style":138},"150","Optimised",[104,220],{"x":142,"y":221,"width":144,"height":145,"rx":146,"fill":126,"stroke":126,"style":147},"134",[129,223,225],{"x":150,"y":224,"fill":126,"style":152,"textAnchor":153},"154","preconnect ×2",[104,227],{"x":169,"y":221,"width":170,"height":145,"rx":146,"fill":202,"stroke":203,"style":204},[129,229,230],{"x":175,"y":224,"fill":126,"style":208,"textAnchor":153},"font preload",[104,232],{"x":169,"y":233,"width":170,"height":234,"rx":146,"fill":171,"stroke":171,"style":172},"170","26",[129,236,238],{"x":175,"y":237,"fill":126,"style":152,"textAnchor":153},"188","CSS (async)",[129,240,243],{"x":241,"y":224,"fill":126,"style":242},"420","font-size:11.5px;fill-opacity:0.85","font and CSS travel together — nothing blocks paint",[129,245,247],{"x":241,"y":237,"fill":126,"style":246},"font-size:11px;fill-opacity:0.7","saves roughly one full round trip on mobile",[34,249,251],{"id":250},"root-cause-analysis","Root Cause Analysis",[14,253,254,257,258,261,262,265],{},[45,255,256],{},"1. Serialised third-party connections."," The document must connect to ",[50,259,260],{},"googleapis.com",", download CSS, discover a URL on ",[50,263,264],{},"gstatic.com",", connect there, and only then request the font. Neither connection can start before the previous step reveals it.",[14,267,268,271,272,275,276,279],{},[45,269,270],{},"2. A render-blocking stylesheet you do not control."," The Google Fonts CSS is a ",[50,273,274],{},"\u003Clink rel=\"stylesheet\">"," in ",[50,277,278],{},"\u003Chead>",", so paint waits for it. Its response is small but its latency is not, and it sits on the critical path for every visitor.",[14,281,282,285],{},[45,283,284],{},"3. Cache partitioning removed the old benefit."," The historical argument for a shared font CDN was cross-site caching. Modern browsers partition the HTTP cache by top-level site, so a visitor who loaded the same font on another site does not reuse it on yours. The connection cost is now paid by everyone.",[14,287,288,291],{},[45,289,290],{},"4. Preloading the CSS instead of the font."," A common half-fix preloads the stylesheet URL. That accelerates the first hop and does nothing for the second, which is where the bytes are.",[34,293,295],{"id":294},"step-by-step-resolution","Step-by-Step Resolution",[14,297,298,301,302,304,305,308,309,312],{},[45,299,300],{},"1. Warm both origins immediately."," Place these before any stylesheet in ",[50,303,278],{},". The ",[50,306,307],{},"crossorigin"," on the ",[50,310,311],{},"gstatic"," hint is required — fonts are fetched anonymously, and a non-matching preconnect warms a connection nothing will use.",[314,315,320],"pre",{"className":316,"code":317,"language":318,"meta":319,"style":319},"language-html shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u003Clink rel=\"preconnect\" href=\"https:\u002F\u002Ffonts.googleapis.com\">\n\u003Clink rel=\"preconnect\" href=\"https:\u002F\u002Ffonts.gstatic.com\" crossorigin>\n\u003C!-- trade-off: two of your two-to-three preconnect slots are now spent on\n     fonts. If you also preconnect an image CDN and an API, measure LCP after\n     each addition — connections compete for the same early bandwidth. -->\n","html","",[50,321,322,356,381,388,394],{"__ignoreMap":319},[323,324,326,330,334,338,341,345,348,350,353],"span",{"class":156,"line":325},1,[323,327,329],{"class":328},"saISM","\u003C",[323,331,333],{"class":332},"sZBmE","link",[323,335,337],{"class":336},"sPXB4"," rel",[323,339,340],{"class":328},"=",[323,342,344],{"class":343},"sZ8jY","\"preconnect\"",[323,346,347],{"class":336}," href",[323,349,340],{"class":328},[323,351,352],{"class":343},"\"https:\u002F\u002Ffonts.googleapis.com\"",[323,354,355],{"class":328},">\n",[323,357,359,361,363,365,367,369,371,373,376,379],{"class":156,"line":358},2,[323,360,329],{"class":328},[323,362,333],{"class":332},[323,364,337],{"class":336},[323,366,340],{"class":328},[323,368,344],{"class":343},[323,370,347],{"class":336},[323,372,340],{"class":328},[323,374,375],{"class":343},"\"https:\u002F\u002Ffonts.gstatic.com\"",[323,377,378],{"class":336}," crossorigin",[323,380,355],{"class":328},[323,382,384],{"class":156,"line":383},3,[323,385,387],{"class":386},"sjfSM","\u003C!-- trade-off: two of your two-to-three preconnect slots are now spent on\n",[323,389,391],{"class":156,"line":390},4,[323,392,393],{"class":386},"     fonts. If you also preconnect an image CDN and an API, measure LCP after\n",[323,395,397],{"class":156,"line":396},5,[323,398,399],{"class":386},"     each addition — connections compete for the same early bandwidth. -->\n",[14,401,402,403,406],{},"Expected outcome: removes DNS and TLS time from the critical path, typically ",[50,404,405],{},"100–250ms"," on mobile.",[14,408,409,412,413,416],{},[45,410,411],{},"2. Stop the stylesheet from blocking paint."," Load it asynchronously and apply it when it arrives. Text still renders immediately in the fallback because ",[50,414,415],{},"display=swap"," is in the URL.",[314,418,420],{"className":316,"code":419,"language":318,"meta":319,"style":319},"\u003Clink rel=\"stylesheet\" media=\"print\" onload=\"this.media='all'\"\n      href=\"https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Inter:wght@400;700&display=swap\">\n\u003Cnoscript>\n  \u003Clink rel=\"stylesheet\"\n        href=\"https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Inter:wght@400;700&display=swap\">\n\u003C\u002Fnoscript>\n\u003C!-- trade-off: the media=print trick defers application, so the swap happens\n     slightly later and is more visible. Pair it with metric overrides or the\n     later swap becomes a CLS problem instead of an LCP one. -->\n",[50,421,422,465,477,486,500,511,521,527,533],{"__ignoreMap":319},[323,423,424,426,428,430,432,435,438,440,443,446,448,451,454,456,459,462],{"class":156,"line":325},[323,425,329],{"class":328},[323,427,333],{"class":332},[323,429,337],{"class":336},[323,431,340],{"class":328},[323,433,434],{"class":343},"\"stylesheet\"",[323,436,437],{"class":336}," media",[323,439,340],{"class":328},[323,441,442],{"class":343},"\"print\"",[323,444,445],{"class":336}," onload",[323,447,340],{"class":328},[323,449,450],{"class":343},"\"",[323,452,453],{"class":336},"this",[323,455,81],{"class":343},[323,457,458],{"class":328},"media",[323,460,340],{"class":461},"sPARh",[323,463,464],{"class":343},"'all'\"\n",[323,466,467,470,472,475],{"class":156,"line":358},[323,468,469],{"class":336},"      href",[323,471,340],{"class":328},[323,473,474],{"class":343},"\"https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Inter:wght@400;700&display=swap\"",[323,476,355],{"class":328},[323,478,479,481,484],{"class":156,"line":383},[323,480,329],{"class":328},[323,482,483],{"class":332},"noscript",[323,485,355],{"class":328},[323,487,488,491,493,495,497],{"class":156,"line":390},[323,489,490],{"class":328},"  \u003C",[323,492,333],{"class":332},[323,494,337],{"class":336},[323,496,340],{"class":328},[323,498,499],{"class":343},"\"stylesheet\"\n",[323,501,502,505,507,509],{"class":156,"line":396},[323,503,504],{"class":336},"        href",[323,506,340],{"class":328},[323,508,474],{"class":343},[323,510,355],{"class":328},[323,512,514,517,519],{"class":156,"line":513},6,[323,515,516],{"class":328},"\u003C\u002F",[323,518,483],{"class":332},[323,520,355],{"class":328},[323,522,524],{"class":156,"line":523},7,[323,525,526],{"class":386},"\u003C!-- trade-off: the media=print trick defers application, so the swap happens\n",[323,528,530],{"class":156,"line":529},8,[323,531,532],{"class":386},"     slightly later and is more visible. Pair it with metric overrides or the\n",[323,534,536],{"class":156,"line":535},9,[323,537,538],{"class":386},"     later swap becomes a CLS problem instead of an LCP one. -->\n",[14,540,541,542,545],{},"Expected outcome: First Contentful Paint no longer waits on a third-party stylesheet; typically ",[50,543,544],{},"200–500ms"," earlier on a constrained connection.",[14,547,548,551,552,554],{},[45,549,550],{},"3. Preload the actual font file."," Read the exact ",[50,553,66],{}," URL from the Network panel and preload it directly, bypassing the second hop entirely.",[314,556,558],{"className":316,"code":557,"language":318,"meta":319,"style":319},"\u003Clink rel=\"preload\" as=\"font\" type=\"font\u002Fwoff2\" crossorigin\n      href=\"https:\u002F\u002Ffonts.gstatic.com\u002Fs\u002Finter\u002Fv18\u002FUcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2\">\n\u003C!-- trade-off: this URL is versioned and Google rotates it. A stale preload is\n     a wasted high-priority request AND a console warning. Only take this step\n     if you can re-verify the URL on a schedule — otherwise self-host. -->\n",[50,559,560,592,603,608,613],{"__ignoreMap":319},[323,561,562,564,566,568,570,573,576,578,581,584,586,589],{"class":156,"line":325},[323,563,329],{"class":328},[323,565,333],{"class":332},[323,567,337],{"class":336},[323,569,340],{"class":328},[323,571,572],{"class":343},"\"preload\"",[323,574,575],{"class":336}," as",[323,577,340],{"class":328},[323,579,580],{"class":343},"\"font\"",[323,582,583],{"class":336}," type",[323,585,340],{"class":328},[323,587,588],{"class":343},"\"font\u002Fwoff2\"",[323,590,591],{"class":336}," crossorigin\n",[323,593,594,596,598,601],{"class":156,"line":358},[323,595,469],{"class":336},[323,597,340],{"class":328},[323,599,600],{"class":343},"\"https:\u002F\u002Ffonts.gstatic.com\u002Fs\u002Finter\u002Fv18\u002FUcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2\"",[323,602,355],{"class":328},[323,604,605],{"class":156,"line":383},[323,606,607],{"class":386},"\u003C!-- trade-off: this URL is versioned and Google rotates it. A stale preload is\n",[323,609,610],{"class":156,"line":390},[323,611,612],{"class":386},"     a wasted high-priority request AND a console warning. Only take this step\n",[323,614,615],{"class":156,"line":396},[323,616,617],{"class":386},"     if you can re-verify the URL on a schedule — otherwise self-host. -->\n",[14,619,620,621,624],{},"Expected outcome: the font download starts with the document rather than after two dependent responses, usually ",[50,622,623],{},"250–500ms"," earlier.",[14,626,627,630,631,633,634,81],{},[45,628,629],{},"4. Prefer self-hosting where you can."," Downloading the subsetted ",[50,632,66],{}," files into your own origin removes both third-party connections, gives you a stable filename you can preload safely, and lets you apply your own immutable caching as described in ",[18,635,637],{"href":636},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fhttp-cache-control-headers-explained\u002F","HTTP Cache-Control headers explained",[314,639,643],{"className":640,"code":641,"language":642,"meta":319,"style":319},"language-css shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F* Self-hosted: one origin, one hop, a filename your build controls. *\u002F\n@font-face {\n  font-family: \"Inter\";\n  src: url(\"\u002Ffonts\u002Finter-latin-var.woff2\") format(\"woff2-variations\");\n  font-weight: 100 900;\n  font-display: swap;\n  unicode-range: U+0000-00FF, U+2000-206F;\n}\n\u002F* trade-off: you now own updates and per-browser format coverage. For a Latin\n   audience on evergreen browsers that is a single WOFF2 file and no ongoing\n   work; for a multi-script site the vendor's per-range slicing is real value. *\u002F\n","css",[50,644,645,650,658,672,702,717,729,747,752,757,763],{"__ignoreMap":319},[323,646,647],{"class":156,"line":325},[323,648,649],{"class":386},"\u002F* Self-hosted: one origin, one hop, a filename your build controls. *\u002F\n",[323,651,652,655],{"class":156,"line":358},[323,653,654],{"class":461},"@font-face",[323,656,657],{"class":328}," {\n",[323,659,660,663,666,669],{"class":156,"line":383},[323,661,662],{"class":336},"  font-family",[323,664,665],{"class":328},": ",[323,667,668],{"class":343},"\"Inter\"",[323,670,671],{"class":328},";\n",[323,673,674,677,679,682,685,688,691,694,696,699],{"class":156,"line":390},[323,675,676],{"class":336},"  src",[323,678,665],{"class":328},[323,680,681],{"class":336},"url",[323,683,684],{"class":328},"(",[323,686,687],{"class":343},"\"\u002Ffonts\u002Finter-latin-var.woff2\"",[323,689,690],{"class":328},") ",[323,692,693],{"class":336},"format",[323,695,684],{"class":328},[323,697,698],{"class":343},"\"woff2-variations\"",[323,700,701],{"class":328},");\n",[323,703,704,707,709,712,715],{"class":156,"line":396},[323,705,706],{"class":336},"  font-weight",[323,708,665],{"class":328},[323,710,711],{"class":336},"100",[323,713,714],{"class":336}," 900",[323,716,671],{"class":328},[323,718,719,722,724,727],{"class":156,"line":513},[323,720,721],{"class":336},"  font-display",[323,723,665],{"class":328},[323,725,726],{"class":336},"swap",[323,728,671],{"class":328},[323,730,731,734,736,739,742,745],{"class":156,"line":523},[323,732,733],{"class":336},"  unicode-range",[323,735,665],{"class":328},[323,737,738],{"class":336},"U+0000-00FF",[323,740,741],{"class":328},", ",[323,743,744],{"class":336},"U+2000-206F",[323,746,671],{"class":328},[323,748,749],{"class":156,"line":529},[323,750,751],{"class":328},"}\n",[323,753,754],{"class":156,"line":535},[323,755,756],{"class":386},"\u002F* trade-off: you now own updates and per-browser format coverage. For a Latin\n",[323,758,760],{"class":156,"line":759},10,[323,761,762],{"class":386},"   audience on evergreen browsers that is a single WOFF2 file and no ongoing\n",[323,764,766],{"class":156,"line":765},11,[323,767,768],{"class":386},"   work; for a multi-script site the vendor's per-range slicing is real value. *\u002F\n",[14,770,771],{},"Expected outcome: eliminates two DNS lookups and two TLS handshakes, and makes the preload permanently safe.",[34,773,775],{"id":774},"verification","Verification",[14,777,778],{},"Reload with an empty cache and confirm three things in the Network panel: the font request starts within the first few hundred milliseconds, its initiator is the document rather than a stylesheet, and no request is marked render-blocking except your own critical CSS.",[14,780,781],{},"Then confirm the metric moved. Compare LCP before and after on a throttled mobile profile, and watch specifically the render-delay portion — that is where a font fix lands. If render delay is unchanged, your LCP element was probably an image and the font was never the constraint.",[14,783,784],{},"Guard it in CI so a redesign cannot reintroduce the blocking stylesheet:",[314,786,790],{"className":787,"code":788,"language":789,"meta":319,"style":319},"language-json shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","{ \"ci\": { \"assert\": { \"assertions\": {\n  \"render-blocking-resources\": [\"error\", { \"maxNumericValue\": 200 }],\n  \"uses-rel-preconnect\": [\"warn\", { \"minScore\": 1 }],\n  \"font-display\": [\"error\", { \"minScore\": 1 }]\n} } } }\n","json",[50,791,792,814,839,860,880],{"__ignoreMap":319},[323,793,794,797,800,803,806,808,811],{"class":156,"line":325},[323,795,796],{"class":328},"{ ",[323,798,799],{"class":332},"\"ci\"",[323,801,802],{"class":328},": { ",[323,804,805],{"class":332},"\"assert\"",[323,807,802],{"class":328},[323,809,810],{"class":332},"\"assertions\"",[323,812,813],{"class":328},": {\n",[323,815,816,819,822,825,828,831,833,836],{"class":156,"line":358},[323,817,818],{"class":332},"  \"render-blocking-resources\"",[323,820,821],{"class":328},": [",[323,823,824],{"class":343},"\"error\"",[323,826,827],{"class":328},", { ",[323,829,830],{"class":332},"\"maxNumericValue\"",[323,832,665],{"class":328},[323,834,835],{"class":336},"200",[323,837,838],{"class":328}," }],\n",[323,840,841,844,846,849,851,854,856,858],{"class":156,"line":383},[323,842,843],{"class":332},"  \"uses-rel-preconnect\"",[323,845,821],{"class":328},[323,847,848],{"class":343},"\"warn\"",[323,850,827],{"class":328},[323,852,853],{"class":332},"\"minScore\"",[323,855,665],{"class":328},[323,857,121],{"class":336},[323,859,838],{"class":328},[323,861,862,865,867,869,871,873,875,877],{"class":156,"line":390},[323,863,864],{"class":332},"  \"font-display\"",[323,866,821],{"class":328},[323,868,824],{"class":343},[323,870,827],{"class":328},[323,872,853],{"class":332},[323,874,665],{"class":328},[323,876,121],{"class":336},[323,878,879],{"class":328}," }]\n",[323,881,882],{"class":156,"line":396},[323,883,884],{"class":328},"} } } }\n",[14,886,887],{},"In the field, segment LCP by first versus repeat visit. The whole cost described here is paid once per visitor per cache lifetime, so the improvement appears almost entirely in the first-visit population.",[34,889,891],{"id":890},"faq","FAQ",[893,894,897,901],"details",{"className":895},[896],"faq-item",[898,899,900],"summary",{},"Is it safe to preload a fonts.gstatic.com URL?",[14,902,903],{},"Only if you re-verify it. Google rotates the versioned path when it updates a face, and a preload pointing at a retired URL spends critical-path bandwidth on a 404 while the real font is fetched separately. If you cannot check the URL on a schedule, either skip the preload and rely on preconnect, or self-host the file so the filename is yours.",[893,905,907,910],{"className":906},[896],[898,908,909],{},"Does the media=\"print\" trick hurt accessibility?",[14,911,912,913,916,917,920,921,924,925,928],{},"No — it defers only when the stylesheet is ",[29,914,915],{},"applied",", not whether it is applied. Text is rendered in the fallback immediately and re-rendered in the web font when the CSS arrives, which is the same outcome ",[50,918,919],{},"font-display: swap"," produces. The ",[50,922,923],{},"\u003Cnoscript>"," fallback covers the case where the ",[50,926,927],{},"onload"," handler cannot run.",[893,930,932,935],{"className":931},[896],[898,933,934],{},"How much does self-hosting actually save?",[14,936,937,938,941],{},"On a warm desktop connection, little. On a cold mobile connection it removes two DNS lookups and two TLS handshakes — commonly ",[50,939,940],{},"200–400ms"," before any font byte moves — and it makes the preload reliable, which is often worth more than the handshake saving. Measure on a throttled profile with an empty cache; a fast local test will show almost no difference and mislead you.",[893,943,945,948],{"className":944},[896],[898,946,947],{},"How many weights should I request in the URL?",[14,949,950,951,954],{},"As few as the design actually renders — usually two. Every additional weight in the ",[50,952,953],{},"family="," parameter adds another font file to the response, and the CSS is generated per request, so a URL asking for six weights and two styles produces twelve faces the browser may fetch. Audit which weights appear in your rendered pages rather than which ones the design system defines, and request only those.",[893,956,958,961],{"className":957},[896],[898,959,960],{},"Does the display=swap parameter matter if I also set font-display myself?",[14,962,963,964,966,967,969],{},"It matters when the third-party CSS is what declares the faces, because you cannot edit the ",[50,965,654],{}," rules it generates — the URL parameter is your only control over the descriptor. If you self-host, the parameter is irrelevant and your own stylesheet decides. Leaving ",[50,968,415],{}," off the URL is a common oversight that reintroduces the default block behaviour and a period of invisible text.",[893,971,973,976],{"className":972},[896],[898,974,975],{},"Is the same approach right for other font services?",[14,977,978],{},"The structure is identical, only the hostnames change: a stylesheet on one origin naming files on another. Warm both origins, take the stylesheet off the critical path, and preload the file only if its URL is stable. Some services serve CSS and fonts from a single origin, which removes one connection and makes preconnect simpler — check the Network panel rather than assuming, because vendors change this.",[34,980,982],{"id":981},"related","Related",[39,984,985,990,997],{},[42,986,987,989],{},[18,988,21],{"href":20}," — the complete font pipeline, from discovery to subsetting.",[42,991,992,996],{},[18,993,995],{"href":994},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fresource-hints-and-early-hints\u002F","Resource Hints & Early Hints"," — the rules that decide when a preconnect or preload is worth its cost.",[42,998,999,1003],{},[18,1000,1002],{"href":1001},"\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Ffixing-cls-from-web-font-swap\u002F","Fixing CLS from web font swap"," — stop the faster swap from becoming a layout-shift problem.",[1005,1006,1008],"script",{"type":1007},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"Load Google Fonts without blocking render\",\n  \"description\": \"Remove the serialised third-party chain behind a Google Fonts integration using preconnect, an asynchronously applied stylesheet, a direct font preload, or self-hosting.\",\n  \"step\": [\n    { \"@type\": \"HowToStep\", \"position\": 1, \"name\": \"Preconnect both origins\", \"text\": \"Warm fonts.googleapis.com and fonts.gstatic.com, using crossorigin on the font origin.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render\u002F#step-by-step-resolution\" },\n    { \"@type\": \"HowToStep\", \"position\": 2, \"name\": \"Unblock the stylesheet\", \"text\": \"Load the font CSS with media=print and swap to all on load so paint is not blocked.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render\u002F#step-by-step-resolution\" },\n    { \"@type\": \"HowToStep\", \"position\": 3, \"name\": \"Preload the font file\", \"text\": \"Preload the exact woff2 URL so the download does not wait for two dependent responses.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render\u002F#step-by-step-resolution\" },\n    { \"@type\": \"HowToStep\", \"position\": 4, \"name\": \"Self-host where possible\", \"text\": \"Move the subsetted woff2 to your own origin for a stable filename, one connection and your own cache policy.\", \"url\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render\u002F#step-by-step-resolution\" }\n  ]\n}\n",[1005,1010,1011],{"type":1007},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"Preloading Google Fonts Without Blocking Render\",\n  \"description\": \"Break the serialised two-origin request chain behind the default Google Fonts snippet with preconnect, async CSS, a direct preload or self-hosting.\",\n  \"datePublished\": \"2026-08-01\",\n  \"dateModified\": \"2026-08-01\",\n  \"author\": { \"@type\": \"Organization\", \"name\": \"frontend-performance.com\" },\n  \"publisher\": { \"@type\": \"Organization\", \"name\": \"frontend-performance.com\" },\n  \"mainEntityOfPage\": { \"@type\": \"WebPage\", \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render\u002F\" }\n}\n",[1005,1013,1014],{"type":1007},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    { \"@type\": \"ListItem\", \"position\": 1, \"name\": \"Home\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 2, \"name\": \"Core Web Vitals & Measurement\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 3, \"name\": \"Font Loading & Text Rendering Performance\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002F\" },\n    { \"@type\": \"ListItem\", \"position\": 4, \"name\": \"Preloading Google Fonts Without Blocking Render\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render\u002F\" }\n  ]\n}\n",[1016,1017,1018],"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 .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 .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}",{"title":319,"searchDepth":358,"depth":358,"links":1020},[1021,1022,1023,1024,1025,1026],{"id":36,"depth":358,"text":37},{"id":250,"depth":358,"text":251},{"id":294,"depth":358,"text":295},{"id":774,"depth":358,"text":775},{"id":890,"depth":358,"text":891},{"id":981,"depth":358,"text":982},"Cut the render-blocking stylesheet and the hidden second hop out of a Google Fonts integration without losing the font.","md",{"slug":12,"type":1030,"breadcrumb":1031,"datePublished":1039,"dateModified":1039},"article",[1032,1035,1036,1037],{"name":1033,"url":1034},"Home","\u002F",{"name":26,"url":25},{"name":21,"url":20},{"name":5,"url":1038},"\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render\u002F","2026-08-01",true,"\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render",{"title":5,"description":1043},"The Google Fonts request chain costs two round trips before a font byte moves. Fix it with preconnect, an async stylesheet, an explicit font preload, or self-hosting.","core-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Fpreloading-google-fonts-without-blocking-render\u002Findex","zqhqosWfzk23tItvZTVAeTqxZqX84HSx24k-yfhuERo",[1047,1051],{"title":1048,"path":1049,"stem":1050},"font-display: swap vs optional for LCP","\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Ffont-display-swap-vs-optional-for-lcp","core-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Ffont-display-swap-vs-optional-for-lcp\u002Findex",{"title":1052,"path":1053,"stem":1054},"Measuring LCP with Chrome DevTools","\u002Fcore-web-vitals-measurement\u002Fmeasuring-lcp-with-chrome-devtools","core-web-vitals-measurement\u002Fmeasuring-lcp-with-chrome-devtools\u002Findex",1785622407042]