[{"data":1,"prerenderedAt":1695},["ShallowReactive",2],{"page:\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-cookie-banners":3,"all-docs-nav":1152},{"id":4,"title":5,"body":6,"breadcrumb":1127,"dateModified":1137,"datePublished":1137,"description":1138,"extension":1139,"faq":1140,"meta":1145,"navigation":1146,"path":1147,"seo":1148,"slug":12,"stem":1149,"type":1150,"__hash__":1151},"content\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-cookie-banners\u002Findex.md","Fixing CLS from Cookie Banners",{"type":7,"value":8,"toc":1108},"minimark",[9,13,17,26,31,53,57,63,162,169,316,320,327,496,499,502,506,509,513,529,683,768,783,787,876,971,975,978,982,985,989,1021,1025,1028,1032,1037,1040,1044,1047,1051,1054,1058,1061,1065,1104],[10,11,5],"h1",{"id":12},"fixing-cls-from-cookie-banners",[14,15,16],"p",{},"Consent banners are one of the most common causes of poor Cumulative Layout Shift on otherwise well-built static sites. The page renders, the reader starts reading, and a third-party consent script arrives a second later and injects a banner at the top of the document — pushing the headline, the hero and everything below it down by 120 pixels. On mobile, that single shift often scores 0.15–0.25 on its own, well past the 0.1 \"good\" threshold, on every first visit.",[14,18,19,20,25],{},"The fix is rarely to remove consent handling; it is to change how the banner enters the page. This guide measures the CLS a consent banner caused on a static marketing and docs site, then applies three fixes in order of effectiveness. It is part of ",[21,22,24],"a",{"href":23},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002F","Cumulative Layout Shift Fixes for Static Sites",".",[27,28,30],"h2",{"id":29},"prerequisites","Prerequisites",[32,33,34,47,50],"ul",{},[35,36,37,38,42,43,25],"li",{},"A way to see layout shifts: the Performance panel in Chrome DevTools (Layout Shifts track) or the ",[39,40,41],"code",{},"web-vitals"," attribution build, as in ",[21,44,46],{"href":45},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Fmeasuring-cls-in-the-field-with-web-vitals-js\u002F","Measuring CLS in the Field with web-vitals.js",[35,48,49],{},"Control over the banner's CSS, or the consent manager's configuration options.",[35,51,52],{},"Test in a fresh profile or incognito window, because a stored consent choice hides the banner.",[27,54,56],{"id":55},"step-1-measure-the-shift","Step 1: Measure the Shift",[14,58,59,60,62],{},"Load the page with no stored consent, record in the Performance panel, and inspect the Layout Shift entries. The attribution build of ",[39,61,41],{}," gives the same in the field:",[64,65,70],"pre",{"className":66,"code":67,"language":68,"meta":69,"style":69},"language-js shiki shiki-themes github-light github-dark","import { onCLS } from 'web-vitals\u002Fattribution';\nonCLS(({ value, attribution }) => {\n  console.log(value.toFixed(3), attribution.largestShiftTarget, attribution.largestShiftTime);\n});\n\u002F\u002F 0.182  \"main > header.hero\"  1240\n","js","",[39,71,72,95,124,149,155],{"__ignoreMap":69},[73,74,77,81,85,88,92],"span",{"class":75,"line":76},"line",1,[73,78,80],{"class":79},"szBVR","import",[73,82,84],{"class":83},"sVt8B"," { onCLS } ",[73,86,87],{"class":79},"from",[73,89,91],{"class":90},"sZZnC"," 'web-vitals\u002Fattribution'",[73,93,94],{"class":83},";\n",[73,96,98,102,105,109,112,115,118,121],{"class":75,"line":97},2,[73,99,101],{"class":100},"sScJk","onCLS",[73,103,104],{"class":83},"(({ ",[73,106,108],{"class":107},"s4XuR","value",[73,110,111],{"class":83},", ",[73,113,114],{"class":107},"attribution",[73,116,117],{"class":83}," }) ",[73,119,120],{"class":79},"=>",[73,122,123],{"class":83}," {\n",[73,125,127,130,133,136,139,142,146],{"class":75,"line":126},3,[73,128,129],{"class":83},"  console.",[73,131,132],{"class":100},"log",[73,134,135],{"class":83},"(value.",[73,137,138],{"class":100},"toFixed",[73,140,141],{"class":83},"(",[73,143,145],{"class":144},"sj4cs","3",[73,147,148],{"class":83},"), attribution.largestShiftTarget, attribution.largestShiftTime);\n",[73,150,152],{"class":75,"line":151},4,[73,153,154],{"class":83},"});\n",[73,156,158],{"class":75,"line":157},5,[73,159,161],{"class":160},"sJ8bj","\u002F\u002F 0.182  \"main > header.hero\"  1240\n",[14,163,164,165,168],{},"On the test site, the banner was inserted as the first child of ",[39,166,167],{},"\u003Cbody>"," at 1.24 s on mobile, 128 px tall, shifting the entire page. Lab CLS: 0.18. Field CLS p75 for first visits: 0.21; for returning visits (consent already stored, no banner): 0.02.",[170,171,172,312],"figure",{},[173,174,181,182,181,186,181,190,181,197],"svg",{"viewBox":175,"role":176,"ariaLabelledBy":177,"xmlns":180},"0 0 760 290","img",[178,179],"ckb-shift-title","ckb-shift-desc","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","\n  ",[183,184,185],"title",{"id":178},"An in-flow banner pushes the page down",[187,188,189],"desc",{"id":179},"Two phone-sized wireframes. At 0.9 seconds the page shows header, headline and hero image. At 1.24 seconds a consent banner inserted at the top of the document in normal flow pushes the headline and hero down by 128 pixels, a layout shift of about 0.18. A third wireframe shows the banner as a fixed overlay at the bottom with no shift.",[191,192],"rect",{"x":193,"y":193,"width":194,"height":195,"fill":196},"0","760","290","#ffffff",[198,199,201,202,201,210,201,220,201,227,201,236,201,241,201,245,201,251,201,255,201,258,201,263,201,269,201,273,201,276,201,279,201,282,201,285,201,290,201,293,201,295,201,297,201,304,201,308,181],"g",{"style":200},"font-family:system-ui, sans-serif;font-size:12px","\n    ",[203,204,209],"text",{"x":205,"y":206,"fill":207,"style":208},"380","28","#1f2937","font-size:16px;font-weight:700;text-anchor:middle","In-flow banner vs fixed overlay",[191,211],{"x":212,"y":213,"width":214,"height":215,"rx":216,"fill":217,"stroke":218,"style":219},"60","50","160","210","10","#f8fafc","#d9e2ef","stroke-width:1.5px",[203,221,226],{"x":222,"y":223,"fill":224,"style":225},"140","44","#556071","font-size:11px;text-anchor:middle","0.9 s",[191,228],{"x":229,"y":230,"width":231,"height":232,"rx":145,"fill":233,"opacity":234,"stroke":233,"style":235},"72","62","136","16","#1982c4","0.2","stroke-width:1px",[191,237],{"x":229,"y":238,"width":231,"height":239,"rx":145,"fill":240,"opacity":234,"stroke":240,"style":235},"86","24","#6a4c93",[203,242,244],{"x":222,"y":243,"fill":207,"style":225},"102","headline",[191,246],{"x":229,"y":247,"width":231,"height":248,"rx":145,"fill":249,"opacity":234,"stroke":250,"style":235},"118","90","#8ac926","#5a8a16",[203,252,254],{"x":222,"y":253,"fill":207,"style":225},"168","hero",[191,256],{"x":257,"y":213,"width":214,"height":215,"rx":216,"fill":217,"stroke":218,"style":219},"300",[203,259,262],{"x":205,"y":223,"fill":260,"style":261},"#b32b30","font-size:11px;font-weight:700;text-anchor:middle","1.24 s · in flow · CLS 0.18",[191,264],{"x":265,"y":230,"width":231,"height":212,"rx":145,"fill":266,"opacity":267,"stroke":268,"style":235},"312","#ff595e","0.22","#d83b41",[203,270,272],{"x":205,"y":271,"fill":207,"style":225},"96","consent banner",[191,274],{"x":265,"y":275,"width":231,"height":232,"rx":145,"fill":233,"opacity":234,"stroke":233,"style":235},"128",[191,277],{"x":265,"y":278,"width":231,"height":239,"rx":145,"fill":240,"opacity":234,"stroke":240,"style":235},"150",[191,280],{"x":265,"y":281,"width":231,"height":229,"rx":145,"fill":249,"opacity":234,"stroke":250,"style":235},"180",[191,283],{"x":284,"y":213,"width":214,"height":215,"rx":216,"fill":217,"stroke":218,"style":219},"540",[203,286,289],{"x":287,"y":223,"fill":288,"style":261},"620","#3f6410","fixed overlay · CLS 0.00",[191,291],{"x":292,"y":230,"width":231,"height":232,"rx":145,"fill":233,"opacity":234,"stroke":233,"style":235},"552",[191,294],{"x":292,"y":238,"width":231,"height":239,"rx":145,"fill":240,"opacity":234,"stroke":240,"style":235},[191,296],{"x":292,"y":247,"width":231,"height":248,"rx":145,"fill":249,"opacity":234,"stroke":250,"style":235},[191,298],{"x":292,"y":299,"width":231,"height":300,"rx":145,"fill":301,"opacity":302,"stroke":303,"style":235},"206","46","#ffca3a","0.5","#a97b00",[203,305,307],{"x":287,"y":306,"fill":207,"style":225},"234","banner overlays",[203,309,311],{"x":205,"y":310,"fill":224,"style":225},"282","Moto G Power profile, first visit, no stored consent",[313,314,315],"figcaption",{},"The same banner content, positioned as an overlay instead of in document flow, produces no shift at all.",[27,317,319],{"id":318},"fix-1-make-the-banner-an-overlay","Fix 1: Make the Banner an Overlay",[14,321,322,323,326],{},"A ",[39,324,325],{},"position: fixed"," element does not affect the layout of other elements, so its appearance causes no layout shift. Pin the banner to the bottom of the viewport:",[64,328,332],{"className":329,"code":330,"language":331,"meta":69,"style":69},"language-css shiki shiki-themes github-light github-dark",".consent-banner {\n  position: fixed;\n  inset: auto 0 0 0;            \u002F* bottom edge *\u002F\n  z-index: 50;\n  max-height: 40vh;\n  overflow: auto;\n  padding: 1rem;\n  background: var(--surface);\n  box-shadow: 0 -2px 12px rgb(0 0 0 \u002F 0.12);\n}\n","css",[39,333,334,341,354,377,388,403,415,431,450,490],{"__ignoreMap":69},[73,335,336,339],{"class":75,"line":76},[73,337,338],{"class":100},".consent-banner",[73,340,123],{"class":83},[73,342,343,346,349,352],{"class":75,"line":97},[73,344,345],{"class":144},"  position",[73,347,348],{"class":83},": ",[73,350,351],{"class":144},"fixed",[73,353,94],{"class":83},[73,355,356,359,361,364,367,369,371,374],{"class":75,"line":126},[73,357,358],{"class":144},"  inset",[73,360,348],{"class":83},[73,362,363],{"class":144},"auto",[73,365,366],{"class":144}," 0",[73,368,366],{"class":144},[73,370,366],{"class":144},[73,372,373],{"class":83},";            ",[73,375,376],{"class":160},"\u002F* bottom edge *\u002F\n",[73,378,379,382,384,386],{"class":75,"line":151},[73,380,381],{"class":144},"  z-index",[73,383,348],{"class":83},[73,385,213],{"class":144},[73,387,94],{"class":83},[73,389,390,393,395,398,401],{"class":75,"line":157},[73,391,392],{"class":144},"  max-height",[73,394,348],{"class":83},[73,396,397],{"class":144},"40",[73,399,400],{"class":79},"vh",[73,402,94],{"class":83},[73,404,406,409,411,413],{"class":75,"line":405},6,[73,407,408],{"class":144},"  overflow",[73,410,348],{"class":83},[73,412,363],{"class":144},[73,414,94],{"class":83},[73,416,418,421,423,426,429],{"class":75,"line":417},7,[73,419,420],{"class":144},"  padding",[73,422,348],{"class":83},[73,424,425],{"class":144},"1",[73,427,428],{"class":79},"rem",[73,430,94],{"class":83},[73,432,434,437,439,442,444,447],{"class":75,"line":433},8,[73,435,436],{"class":144},"  background",[73,438,348],{"class":83},[73,440,441],{"class":144},"var",[73,443,141],{"class":83},[73,445,446],{"class":107},"--surface",[73,448,449],{"class":83},");\n",[73,451,453,456,458,460,463,466,469,471,474,476,478,480,482,485,488],{"class":75,"line":452},9,[73,454,455],{"class":144},"  box-shadow",[73,457,348],{"class":83},[73,459,193],{"class":144},[73,461,462],{"class":144}," -2",[73,464,465],{"class":79},"px",[73,467,468],{"class":144}," 12",[73,470,465],{"class":79},[73,472,473],{"class":144}," rgb",[73,475,141],{"class":83},[73,477,193],{"class":144},[73,479,366],{"class":144},[73,481,366],{"class":144},[73,483,484],{"class":83}," \u002F ",[73,486,487],{"class":144},"0.12",[73,489,449],{"class":83},[73,491,493],{"class":75,"line":492},10,[73,494,495],{"class":83},"}\n",[14,497,498],{},"Most consent platforms offer a \"bottom bar\" or \"floating\" layout in configuration; use it rather than a top bar. If the vendor's CSS cannot be changed, a small override stylesheet loaded after it works. Two cautions: a fixed banner must not cover essential content without a way to dismiss it, and it must be reachable and operable by keyboard, with focus moved to it when it appears if it blocks interaction.",[14,500,501],{},"This change alone took lab CLS from 0.18 to 0.00 and field CLS p75 on first visits from 0.21 to 0.03.",[27,503,505],{"id":504},"fix-2-keep-the-banner-off-the-lcp-path","Fix 2: Keep the Banner Off the LCP Path",[14,507,508],{},"A large banner can become the LCP element: on a small phone, a banner with three paragraphs of text may be the biggest block in the viewport, so LCP waits for the consent script. Keep the banner compact — a sentence and two buttons, with details behind a \"Settings\" link — and render it after the page's main content. On the test site, trimming the banner from 94 to 31 words kept the hero headline as the LCP element and moved mobile lab LCP from 2.4 s back to 1.6 s.",[27,510,512],{"id":511},"fix-3-load-the-consent-script-late-but-not-too-late","Fix 3: Load the Consent Script Late — but Not Too Late",[14,514,515,516,520,521,524,525,528],{},"Two parts of consent handling have different timing needs. The ",[517,518,519],"strong",{},"gate"," — the logic that stops analytics or marketing tags from running before consent — must run before those tags, which in practice means early. The ",[517,522,523],{},"banner UI"," can load after first paint. Many consent platforms load both as one 60–120 KB script in the ",[39,526,527],{},"\u003Chead>",". Split them where possible:",[64,530,534],{"className":531,"code":532,"language":533,"meta":69,"style":69},"language-html shiki shiki-themes github-light github-dark","\u003C!-- in \u003Chead>: tiny gate, ~1 KB, no UI -->\n\u003Cscript>\n  window.consent = JSON.parse(localStorage.getItem('consent') || 'null');\n  window.consentReady = new Promise((r) => (window.__setConsent = r));\n\u003C\u002Fscript>\n\u003C!-- after content: banner UI, only when no stored choice -->\n\u003Cscript type=\"module\">\n  if (!window.consent) import('\u002Fjs\u002Fconsent-banner.js');\n\u003C\u002Fscript>\n","html",[39,535,536,541,553,591,622,631,636,652,675],{"__ignoreMap":69},[73,537,538],{"class":75,"line":76},[73,539,540],{"class":160},"\u003C!-- in \u003Chead>: tiny gate, ~1 KB, no UI -->\n",[73,542,543,546,550],{"class":75,"line":97},[73,544,545],{"class":83},"\u003C",[73,547,549],{"class":548},"s9eBZ","script",[73,551,552],{"class":83},">\n",[73,554,555,558,561,564,566,569,572,575,577,580,583,586,589],{"class":75,"line":126},[73,556,557],{"class":83},"  window.consent ",[73,559,560],{"class":79},"=",[73,562,563],{"class":144}," JSON",[73,565,25],{"class":83},[73,567,568],{"class":100},"parse",[73,570,571],{"class":83},"(localStorage.",[73,573,574],{"class":100},"getItem",[73,576,141],{"class":83},[73,578,579],{"class":90},"'consent'",[73,581,582],{"class":83},") ",[73,584,585],{"class":79},"||",[73,587,588],{"class":90}," 'null'",[73,590,449],{"class":83},[73,592,593,596,598,601,604,607,610,612,614,617,619],{"class":75,"line":151},[73,594,595],{"class":83},"  window.consentReady ",[73,597,560],{"class":79},[73,599,600],{"class":79}," new",[73,602,603],{"class":144}," Promise",[73,605,606],{"class":83},"((",[73,608,609],{"class":107},"r",[73,611,582],{"class":83},[73,613,120],{"class":79},[73,615,616],{"class":83}," (window.__setConsent ",[73,618,560],{"class":79},[73,620,621],{"class":83}," r));\n",[73,623,624,627,629],{"class":75,"line":157},[73,625,626],{"class":83},"\u003C\u002F",[73,628,549],{"class":548},[73,630,552],{"class":83},[73,632,633],{"class":75,"line":405},[73,634,635],{"class":160},"\u003C!-- after content: banner UI, only when no stored choice -->\n",[73,637,638,640,642,645,647,650],{"class":75,"line":417},[73,639,545],{"class":83},[73,641,549],{"class":548},[73,643,644],{"class":100}," type",[73,646,560],{"class":83},[73,648,649],{"class":90},"\"module\"",[73,651,552],{"class":83},[73,653,654,657,660,663,666,668,670,673],{"class":75,"line":433},[73,655,656],{"class":79},"  if",[73,658,659],{"class":83}," (",[73,661,662],{"class":79},"!",[73,664,665],{"class":83},"window.consent) ",[73,667,80],{"class":79},[73,669,141],{"class":83},[73,671,672],{"class":90},"'\u002Fjs\u002Fconsent-banner.js'",[73,674,449],{"class":83},[73,676,677,679,681],{"class":75,"line":452},[73,678,626],{"class":83},[73,680,549],{"class":548},[73,682,552],{"class":83},[170,684,685,765],{},[173,686,181,691,181,694,181,697,181,700],{"viewBox":687,"role":176,"ariaLabelledBy":688,"xmlns":180},"0 0 760 240",[689,690],"ckb-split-title","ckb-split-desc",[183,692,693],{"id":689},"Splitting the consent gate from the banner UI",[187,695,696],{"id":690},"Before, one 88 kilobyte vendor script in the head blocked rendering and injected the banner. After, a 1 kilobyte inline gate runs in the head and holds tags until consent is known, the page renders, and a 3 kilobyte banner module loads after content only for visitors without a stored choice.",[191,698],{"x":193,"y":193,"width":194,"height":699,"fill":196},"240",[198,701,201,702,201,705,201,711,201,717,201,722,201,725,201,729,201,733,201,738,201,743,201,745,201,748,201,752,201,756,201,761,181],{"style":200},[203,703,704],{"x":205,"y":206,"fill":207,"style":208},"What runs before first paint",[203,706,710],{"x":707,"y":708,"fill":207,"style":709},"30","84","font-weight:700","Before",[191,712],{"x":713,"y":714,"width":257,"height":707,"rx":715,"fill":266,"opacity":716,"stroke":268,"style":235},"120","66","4","0.28",[203,718,721],{"x":719,"y":238,"fill":207,"style":720},"270","text-anchor:middle","vendor script 88 KB (gate + UI)",[191,723],{"x":724,"y":714,"width":222,"height":707,"rx":715,"fill":233,"opacity":234,"stroke":233,"style":235},"420",[203,726,728],{"x":727,"y":238,"fill":207,"style":720},"490","render",[203,730,732],{"x":707,"y":731,"fill":207,"style":709},"164","After",[191,734],{"x":713,"y":735,"width":736,"height":707,"rx":715,"fill":249,"opacity":737,"stroke":250,"style":235},"146","20","0.45",[203,739,742],{"x":740,"y":741,"fill":288,"style":261},"130","194","gate 1 KB",[191,744],{"x":222,"y":735,"width":222,"height":707,"rx":715,"fill":233,"opacity":234,"stroke":233,"style":235},[203,746,728],{"x":215,"y":747,"fill":207,"style":720},"166",[191,749],{"x":195,"y":735,"width":750,"height":707,"rx":715,"fill":301,"opacity":751,"stroke":303,"style":235},"80","0.38",[203,753,755],{"x":754,"y":747,"fill":207,"style":225},"330","banner 3 KB",[203,757,760],{"x":758,"y":747,"fill":224,"style":759},"390","font-size:11px","only without stored consent",[203,762,764],{"x":205,"y":763,"fill":224,"style":225},"226","Tags still wait for the gate; only the UI moved after paint",[313,766,767],{},"The legally important part — blocking tags until consent — stays early; the heavy part moves out of the way.",[14,769,770,771,774,775,778,779,25],{},"Analytics and marketing tags wait on ",[39,772,773],{},"consentReady"," or read ",[39,776,777],{},"window.consent",", so nothing fires before a choice exists. A self-built banner like this is about 3 KB; the vendor script it replaced was 88 KB and blocked the main thread for 140 ms on mobile. Whether a self-built banner meets your legal requirements is a question for whoever owns compliance; the performance pattern is the same with a vendor that offers an asynchronous loader. The broader approach to vendor scripts is in ",[21,780,782],{"href":781},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002F","Third-Party Script Performance on Static Sites",[27,784,786],{"id":785},"measured-impact","Measured Impact",[788,789,790,806],"table",{},[791,792,793],"thead",{},[794,795,796,800,803],"tr",{},[797,798,799],"th",{},"Measure (first visit, mobile)",[797,801,802],{},"Vendor top bar, sync script",[797,804,805],{},"Fixed bottom bar + split loading",[807,808,809,821,832,843,854,865],"tbody",{},[794,810,811,815,818],{},[812,813,814],"td",{},"Lab CLS",[812,816,817],{},"0.18",[812,819,820],{},"0.00",[794,822,823,826,829],{},[812,824,825],{},"Field CLS p75 (first visits)",[812,827,828],{},"0.21",[812,830,831],{},"0.03",[794,833,834,837,840],{},[812,835,836],{},"Lab LCP",[812,838,839],{},"2.4 s",[812,841,842],{},"1.6 s",[794,844,845,848,851],{},[812,846,847],{},"Consent JavaScript before first paint",[812,849,850],{},"88 KB",[812,852,853],{},"1 KB",[794,855,856,859,862],{},[812,857,858],{},"Total Blocking Time",[812,860,861],{},"210 ms",[812,863,864],{},"40 ms",[794,866,867,870,873],{},[812,868,869],{},"Consent acceptance rate",[812,871,872],{},"61%",[812,874,875],{},"63%",[170,877,878,968],{},[173,879,181,884,181,887,181,890,181,892],{"viewBox":880,"role":176,"ariaLabelledBy":881,"xmlns":180},"0 0 760 270",[882,883],"ckb-res-title","ckb-res-desc",[183,885,886],{"id":882},"First-visit metrics before and after",[187,888,889],{"id":883},"Three paired bars. Field CLS p75 on first visits fell from 0.21 to 0.03. Lab LCP fell from 2.4 to 1.6 seconds. Total Blocking Time fell from 210 to 40 milliseconds. Consent acceptance stayed roughly the same, 61 to 63 percent.",[191,891],{"x":193,"y":193,"width":194,"height":719,"fill":196},[198,893,201,894,201,897,201,901,201,903,201,906,201,910,201,914,201,918,201,921,201,924,201,927,201,932,201,936,201,941,201,945,201,949,201,952,201,955,201,960,201,964,181],{"style":200},[203,895,896],{"x":205,"y":206,"fill":207,"style":208},"First visit, mobile: before (red) and after (green)",[203,898,900],{"x":740,"y":212,"fill":207,"style":899},"font-weight:700;text-anchor:middle","CLS p75",[75,902],{"x1":213,"y1":215,"x2":215,"y2":215,"stroke":224,"style":219},[191,904],{"x":905,"y":905,"width":213,"height":222,"fill":266,"opacity":716,"stroke":268,"style":235},"70",[203,907,828],{"x":908,"y":909,"fill":207,"style":225},"95","64",[191,911],{"x":222,"y":912,"width":213,"height":736,"fill":249,"opacity":913,"stroke":250,"style":235},"190","0.4",[203,915,831],{"x":916,"y":917,"fill":288,"style":261},"165","184",[203,919,920],{"x":205,"y":212,"fill":207,"style":899},"lab LCP (s)",[75,922],{"x1":257,"y1":215,"x2":923,"y2":215,"stroke":224,"style":219},"460",[191,925],{"x":926,"y":750,"width":213,"height":740,"fill":266,"opacity":716,"stroke":268,"style":235},"320",[203,928,931],{"x":929,"y":930,"fill":207,"style":225},"345","74","2.4",[191,933],{"x":758,"y":934,"width":213,"height":935,"fill":249,"opacity":913,"stroke":250,"style":235},"123","87",[203,937,940],{"x":938,"y":939,"fill":288,"style":261},"415","117","1.6",[203,942,944],{"x":943,"y":212,"fill":207,"style":899},"630","TBT (ms)",[75,946],{"x1":947,"y1":215,"x2":948,"y2":215,"stroke":224,"style":219},"550","710",[191,950],{"x":951,"y":750,"width":213,"height":740,"fill":266,"opacity":716,"stroke":268,"style":235},"570",[203,953,215],{"x":954,"y":930,"fill":207,"style":225},"595",[191,956],{"x":957,"y":958,"width":213,"height":959,"fill":249,"opacity":913,"stroke":250,"style":235},"640","185","25",[203,961,397],{"x":962,"y":963,"fill":288,"style":261},"665","179",[203,965,967],{"x":205,"y":966,"fill":224,"style":225},"248","Consent acceptance: 61% before, 63% after — no loss from the lighter banner",[313,969,970],{},"All three Core Web Vitals-related numbers improved without any change in the rate at which readers gave consent.",[27,972,974],{"id":973},"other-banners-same-problem","Other Banners, Same Problem",[14,976,977],{},"Consent banners are the most common late-inserted element, but not the only one. Promotional bars (\"New: version 4 is out\"), newsletter prompts, app-install banners and maintenance notices are usually added by a script after load and pushed into the top of the document for visibility — the exact pattern that caused the shift above. The same three rules apply to all of them. Render them at build time when the content is known in advance, so they are in the HTML from the first paint and cause no shift; a site-wide announcement can be a front-matter field or data file read by the layout. When they must be dynamic, use a fixed overlay or reserve their space with a placeholder of known height. And load their scripts after the main content, never in the head. On this site, an announcement bar injected by a marketing tool had been adding a further 0.06 of CLS on top of the consent banner; moving its text into a build-time data file removed it entirely and let the marketing team keep editing it through the CMS.",[27,979,981],{"id":980},"returning-visitors-and-consent-changes","Returning Visitors and Consent Changes",[14,983,984],{},"Returning readers with a stored choice should see no banner and load no banner code at all; check this path too, because some vendors load their full script on every visit just to read the stored cookie. A \"Cookie settings\" link in the footer lets readers change their choice later by loading the banner UI on demand. On this site, returning visits loaded 1 KB of consent code instead of 88 KB, which also improved INP for returning readers because the vendor script had registered listeners on every page.",[27,986,988],{"id":987},"pitfalls-rollback","Pitfalls & Rollback",[32,990,991,997,1003,1009,1015],{},[35,992,993,996],{},[517,994,995],{},"Testing with consent stored."," The banner never appears in your usual browser profile; test in a fresh profile.",[35,998,999,1002],{},[517,1000,1001],{},"Top-of-page in-flow banners."," They shift everything; use a fixed overlay.",[35,1004,1005,1008],{},[517,1006,1007],{},"Overlays that trap readers."," A fixed banner must be dismissible, keyboard accessible, and must not hide essential controls on small screens.",[35,1010,1011,1014],{},[517,1012,1013],{},"Deferring the gate along with the UI."," Tags must still wait for consent; only the UI should be late.",[35,1016,1017,1020],{},[517,1018,1019],{},"Rollback:"," revert to the vendor's default layout in its configuration; the gate and banner split can be reverted independently.",[27,1022,1024],{"id":1023},"conclusion","Conclusion",[14,1026,1027],{},"A consent banner inserted into document flow was responsible for most of a static site's first-visit layout shift. Making it a fixed overlay removed the shift entirely, keeping it compact kept it from becoming the LCP element, and splitting a 1 KB consent gate from a lazily loaded banner UI took 87 KB of JavaScript off the critical path. First-visit CLS fell from 0.21 to 0.03 and LCP from 2.4 to 1.6 seconds, with consent rates unchanged.",[27,1029,1031],{"id":1030},"faq","FAQ",[1033,1034,1036],"h3",{"id":1035},"why-do-cookie-banners-cause-layout-shift","Why do cookie banners cause layout shift?",[14,1038,1039],{},"Many banners are inserted at the top of the page after the content has rendered, pushing everything down. Others are inserted at the bottom in normal document flow, shifting the footer and anything below. Both count as unexpected layout shifts.",[1033,1041,1043],{"id":1042},"does-a-fixed-position-banner-cause-cls","Does a fixed-position banner cause CLS?",[14,1045,1046],{},"No. An element with position fixed or sticky that overlays content does not move other elements, so it contributes no layout shift. Its own appearance is not counted as a shift either.",[1033,1048,1050],{"id":1049},"can-the-consent-banner-be-the-lcp-element","Can the consent banner be the LCP element?",[14,1052,1053],{},"Yes, if it is the largest text block visible in the viewport when it appears, which is common on mobile. That makes LCP depend on the consent script's load time. Keep the banner compact or render it after the main content has painted.",[1033,1055,1057],{"id":1056},"should-the-consent-manager-script-load-in-the-head","Should the consent manager script load in the head?",[14,1059,1060],{},"Only the small part that must block other tags until consent is known. The banner UI can load later. Many vendors offer an asynchronous loader; self-hosting the UI or building a small banner yourself removes the third-party dependency entirely.",[27,1062,1064],{"id":1063},"related","Related",[32,1066,1067,1076,1083,1090,1097],{},[35,1068,1069,1072,1073,1075],{},[517,1070,1071],{},"Parent:"," ",[21,1074,24],{"href":23}," — the other sources of shift.",[35,1077,1078,1082],{},[21,1079,1081],{"href":1080},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-late-loading-embeds\u002F","Fixing CLS from Late-Loading Embeds"," — the same pattern for embeds.",[35,1084,1085,1089],{},[21,1086,1088],{"href":1087},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Floading-google-tag-manager-without-hurting-inp\u002F","Loading Google Tag Manager Without Hurting INP"," — tags that wait on consent.",[35,1091,1092,1096],{},[21,1093,1095],{"href":1094},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fself-hosting-analytics-to-cut-third-party-requests\u002F","Self-Hosting Analytics to Cut Third-Party Requests"," — reducing what needs consent.",[35,1098,1099,1103],{},[21,1100,1102],{"href":1101},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-sticky-headers-and-anchor-links\u002F","Fixing CLS from Sticky Headers and Anchor Links"," — another positioning-related shift.",[1105,1106,1107],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":69,"searchDepth":97,"depth":97,"links":1109},[1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1126],{"id":29,"depth":97,"text":30},{"id":55,"depth":97,"text":56},{"id":318,"depth":97,"text":319},{"id":504,"depth":97,"text":505},{"id":511,"depth":97,"text":512},{"id":785,"depth":97,"text":786},{"id":973,"depth":97,"text":974},{"id":980,"depth":97,"text":981},{"id":987,"depth":97,"text":988},{"id":1023,"depth":97,"text":1024},{"id":1030,"depth":97,"text":1031,"children":1121},[1122,1123,1124,1125],{"id":1035,"depth":126,"text":1036},{"id":1042,"depth":126,"text":1043},{"id":1049,"depth":126,"text":1050},{"id":1056,"depth":126,"text":1057},{"id":1063,"depth":97,"text":1064},[1128,1131,1134,1135],{"name":1129,"item":1130},"Home","\u002F",{"name":1132,"item":1133},"Performance Optimization & Core Web Vitals for SSGs","\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002F",{"name":24,"item":23},{"name":5,"item":1136},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-cookie-banners\u002F","2026-09-18","Consent banners are a leading cause of layout shift on static sites. Overlay them, keep them compact, and keep the consent script off the critical path.","md",[1141,1142,1143,1144],{"q":1036,"a":1039},{"q":1043,"a":1046},{"q":1050,"a":1053},{"q":1057,"a":1060},{},true,"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-cookie-banners",{"title":5,"description":1138},"performance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-cookie-banners\u002Findex","article","lxeqjI-WIo-jy58KOHBOMf8olmSzGbOviZbgQTPl8Dw",[1153,1156,1159,1162,1165,1168,1171,1174,1177,1180,1183,1186,1189,1192,1195,1198,1201,1204,1207,1210,1213,1216,1219,1222,1225,1228,1231,1234,1237,1240,1243,1246,1249,1252,1255,1258,1261,1264,1267,1270,1273,1276,1279,1282,1285,1288,1291,1294,1297,1300,1303,1306,1309,1312,1315,1318,1321,1324,1327,1330,1333,1336,1337,1340,1342,1344,1347,1350,1353,1356,1359,1362,1365,1368,1371,1374,1377,1380,1383,1386,1389,1392,1395,1398,1401,1404,1407,1410,1413,1416,1419,1422,1425,1428,1431,1434,1437,1440,1443,1446,1449,1452,1455,1458,1461,1464,1467,1470,1472,1475,1477,1480,1482,1485,1488,1491,1494,1497,1500,1503,1506,1509,1512,1515,1518,1521,1524,1527,1530,1533,1536,1539,1542,1545,1548,1551,1554,1557,1560,1563,1566,1569,1572,1575,1578,1581,1584,1587,1590,1593,1596,1599,1602,1605,1608,1611,1614,1617,1620,1623,1626,1629,1632,1635,1638,1641,1644,1647,1650,1653,1656,1659,1662,1665,1668,1671,1674,1677,1680,1683,1686,1689,1692],{"path":1154,"title":1155},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fastro-vs-eleventy-build-times-at-10000-pages","Astro vs Eleventy Build Times at 10,000 Pages",{"path":1157,"title":1158},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fchoosing-between-astro-and-eleventy-for-large-docs","Astro vs Eleventy for Large Docs (1000+ Pages)",{"path":1160,"title":1161},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fcontent-collections-vs-eleventy-data-cascade","Content Collections vs the Eleventy Data Cascade",{"path":1163,"title":1164},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites","Astro vs Eleventy for Documentation Sites",{"path":1166,"title":1167},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fshortcodes-vs-components-for-docs-authors","Shortcodes vs Components for Docs Authors",{"path":1169,"title":1170},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fsidebar-navigation-in-astro-and-eleventy","Sidebar Navigation in Astro and Eleventy",{"path":1172,"title":1173},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fcustomizing-starlight-without-forking-the-theme","Customizing Starlight Without Forking the Theme",{"path":1175,"title":1176},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fdocusaurus-vs-starlight-for-product-documentation","Docusaurus vs Starlight for Product Documentation",{"path":1178,"title":1179},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress","Docs Frameworks: Docusaurus, Starlight and VitePress",{"path":1181,"title":1182},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmdx-vs-markdoc-for-docs-content","MDX vs Markdoc for Docs Content",{"path":1184,"title":1185},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmigrating-from-mkdocs-to-starlight","Migrating from MkDocs to Starlight",{"path":1187,"title":1188},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fversioned-documentation-with-docusaurus","Versioned Documentation with Docusaurus",{"path":1190,"title":1191},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fvitepress-for-library-documentation","VitePress for Library Documentation",{"path":1193,"title":1194},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fhow-to-benchmark-hugo-vs-astro-build-speeds","How to Benchmark Hugo vs Astro Build Speeds",{"path":1196,"title":1197},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fhugo-partialcached-for-faster-builds","Hugo partialCached for Faster Builds",{"path":1199,"title":1200},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories","Hugo Build Times for Large Repositories",{"path":1202,"title":1203},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fprofiling-hugo-templates-with-template-metrics","Profiling Hugo Templates With Template Metrics",{"path":1205,"title":1206},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Freducing-hugo-memory-usage-on-ci-runners","Reducing Hugo Memory Usage on CI Runners",{"path":1208,"title":1209},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fspeeding-up-hugo-builds-with-render-hooks-and-caching","Speeding Up Hugo Builds with Render Hooks & Caching",{"path":1211,"title":1212},"\u002Fchoosing-the-right-static-site-generator-for-production","Choosing the Right Static Site Generator for Production",{"path":1214,"title":1215},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Feleventy-vs-jekyll-for-markdown-heavy-blogs","Eleventy vs Jekyll for Markdown-Heavy Blogs",{"path":1217,"title":1218},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem","Jekyll Plugin Ecosystem",{"path":1220,"title":1221},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Freplacing-jekyll-plugins-when-migrating-to-eleventy","Replacing Jekyll Plugins When Migrating to Eleventy",{"path":1223,"title":1224},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Frunning-jekyll-on-github-pages-without-plugins","Running Jekyll on GitHub Pages Without Plugins",{"path":1226,"title":1227},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Fspeeding-up-slow-jekyll-builds","Speeding Up Slow Jekyll Builds",{"path":1229,"title":1230},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Fupgrading-jekyll-and-ruby-versions-safely","Upgrading Jekyll and Ruby Versions Safely",{"path":1232,"title":1233},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fconverting-front-matter-at-scale-during-migration","Converting Front Matter at Scale During Migration",{"path":1235,"title":1236},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators","Migrating Between Static Site Generators",{"path":1238,"title":1239},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fkeeping-redirects-working-after-an-ssg-migration","Keeping Redirects Working After an SSG Migration",{"path":1241,"title":1242},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-a-docs-site-from-jekyll-to-hugo","Migrating a Docs Site From Jekyll to Hugo",{"path":1244,"title":1245},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-from-gatsby-to-astro","Migrating from Gatsby to Astro",{"path":1247,"title":1248},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-from-hugo-to-astro-without-breaking-urls","Migrating From Hugo to Astro Without Breaking URLs",{"path":1250,"title":1251},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-wordpress-to-a-static-site-generator","Migrating WordPress to a Static Site Generator",{"path":1253,"title":1254},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fporting-shortcodes-and-includes-between-generators","Porting Shortcodes and Includes Between Generators",{"path":1256,"title":1257},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fhandling-dynamic-routes-in-nextjs-static-export","Handling Dynamic Routes in Next.js Static Export",{"path":1259,"title":1260},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites","Next.js Static Export for Content Sites",{"path":1262,"title":1263},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fmigrating-from-gatsby-to-nextjs-static-export","Migrating from Gatsby to Next.js Static Export",{"path":1265,"title":1266},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fnextjs-app-router-static-export-limitations","Next.js App Router Static Export Limitations",{"path":1268,"title":1269},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fnextjs-static-export-vs-astro-for-marketing-sites","Next.js Static Export vs Astro for Marketing",{"path":1271,"title":1272},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Foptimizing-images-in-nextjs-static-export","Optimizing Images in Next.js Static Export",{"path":1274,"title":1275},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fadding-pagefind-to-an-astro-site","Adding Pagefind to an Astro Site",{"path":1277,"title":1278},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fbuilding-a-lunr-index-at-build-time-in-eleventy","Building a Lunr Index at Build Time in Eleventy",{"path":1280,"title":1281},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites","Search for Static Sites",{"path":1283,"title":1284},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Findexing-hugo-sites-with-pagefind","Indexing Hugo Sites with Pagefind",{"path":1286,"title":1287},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fmultilingual-search-on-static-sites","Multilingual Search on Static Sites",{"path":1289,"title":1290},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fpagefind-vs-algolia-docsearch","Pagefind vs Algolia DocSearch",{"path":1292,"title":1293},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fsearch-index-size-budgets-for-large-docs","Search Index Size Budgets for Large Docs",{"path":1295,"title":1296},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fbest-ssg-for-technical-writers-without-coding-experience","Best SSG for Non-Developer Technical Writers",{"path":1298,"title":1299},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fchoosing-an-ssg-for-api-reference-documentation","Choosing an SSG for API Reference Documentation",{"path":1301,"title":1302},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fevaluating-ssg-accessibility-defaults","Evaluating SSG Accessibility Defaults",{"path":1304,"title":1305},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix","SSG Framework Selection Matrix",{"path":1307,"title":1308},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fpicking-an-ssg-for-a-multi-language-documentation-site","Picking an SSG for a Multi-Language Docs Site",{"path":1310,"title":1311},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fssg-selection-checklist-for-engineering-teams","SSG Selection Checklist for Engineering Teams",{"path":1313,"title":1314},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Ftotal-cost-of-ownership-for-static-site-generators","Total Cost of Ownership for Static Site Generators",{"path":1316,"title":1317},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcache-busting-with-content-hashed-filenames","Cache Busting with Content-Hashed Filenames",{"path":1319,"title":1320},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs","CDN Caching Rules for SSGs",{"path":1322,"title":1323},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fpurging-the-cdn-cache-after-a-static-deploy","Purging the CDN Cache After a Static Deploy",{"path":1325,"title":1326},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fsetting-cache-control-headers-on-cloudflare-pages","Cache-Control Headers on Cloudflare Pages",{"path":1328,"title":1329},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fsetting-up-proper-cache-headers-on-netlify","Proper Cache Headers on Netlify for SSGs",{"path":1331,"title":1332},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fstale-while-revalidate-for-static-html","Stale-While-Revalidate for Static HTML",{"path":1334,"title":1335},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Feliminating-layout-shift-from-web-fonts","Eliminating Layout Shift From Web Fonts",{"path":1147,"title":5},{"path":1338,"title":1339},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-late-loading-embeds","Fixing CLS From Late-Loading Embeds",{"path":1341,"title":1102},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-sticky-headers-and-anchor-links",{"path":1343,"title":24},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites",{"path":1345,"title":1346},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Fmeasuring-cls-in-the-field-with-web-vitals-js","Measuring CLS in the Field With web-vitals.js",{"path":1348,"title":1349},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Freserving-space-for-images-and-embeds-to-stop-layout-shift","Reserving Space for Images and Embeds",{"path":1351,"title":1352},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Ffont-display-optional-vs-swap","font-display: optional vs swap",{"path":1354,"title":1355},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites","Font Loading Strategies for Static Sites",{"path":1357,"title":1358},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fmetric-matched-fallback-fonts-with-size-adjust","Metric-Matched Fallback Fonts with size-adjust",{"path":1360,"title":1361},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fpreloading-fonts-without-double-downloads","Preloading Fonts Without Double Downloads",{"path":1363,"title":1364},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fself-hosting-google-fonts-to-eliminate-layout-shift","Self-Host Google Fonts to Eliminate Layout Shift",{"path":1366,"title":1367},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fsubsetting-variable-fonts-for-faster-first-render","Subsetting Variable Fonts for Faster First Render",{"path":1369,"title":1370},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fbuilding-an-image-cdn-pipeline-for-static-sites","Building an Image CDN Pipeline for Static Sites",{"path":1372,"title":1373},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fgenerating-open-graph-images-at-build-time","Generating Open Graph Images at Build Time",{"path":1375,"title":1376},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro","Image Optimization Pipelines in Astro",{"path":1378,"title":1379},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Flazy-loading-images-without-hurting-lcp","Lazy-Loading Images Without Hurting LCP",{"path":1381,"title":1382},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Foptimizing-webp-images-in-hugo-without-plugins","Optimizing WebP Images in Hugo Without Plugins",{"path":1384,"title":1385},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fresponsive-images-with-srcset-in-eleventy","Responsive Images with srcset in Eleventy",{"path":1387,"title":1388},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fserving-avif-with-fallbacks-on-static-sites","Serving AVIF With Fallbacks on Static Sites",{"path":1390,"title":1391},"\u002Fperformance-optimization-core-web-vitals-for-ssgs","Core Web Vitals Optimization for SSGs",{"path":1393,"title":1394},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fastro-islands-vs-full-hydration-performance","Astro Islands vs Full Hydration Performance",{"path":1396,"title":1397},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fdeferring-hydration-with-client-visible-in-astro","Deferring Hydration with client:visible in Astro",{"path":1399,"title":1400},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fhow-to-reduce-bundle-size-in-eleventy-builds","How to Reduce Bundle Size in Eleventy Builds",{"path":1402,"title":1403},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering","JavaScript Hydration & Partial Rendering",{"path":1405,"title":1406},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fmeasuring-inp-on-static-sites-with-real-user-monitoring","Measuring INP on Static Sites with RUM",{"path":1408,"title":1409},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Freplacing-react-islands-with-web-components","Replacing React Islands with Web Components",{"path":1411,"title":1412},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Feliminating-render-blocking-css-on-static-sites","Eliminating Render-Blocking CSS on Static Sites",{"path":1414,"title":1415},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Ffixing-lcp-on-text-heavy-documentation-pages","Fixing LCP on Text-Heavy Documentation Pages",{"path":1417,"title":1418},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites","Largest Contentful Paint Optimization for Static Sites",{"path":1420,"title":1421},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Fmeasuring-lcp-subparts-with-devtools","Measuring LCP Subparts with DevTools",{"path":1423,"title":1424},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Foptimizing-lcp-on-astro-with-priority-hints","Optimizing LCP on Astro with Priority Hints",{"path":1426,"title":1427},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Freducing-lcp-from-hero-images-on-static-sites","Reducing LCP from Hero Images on Static Sites",{"path":1429,"title":1430},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fcomparing-lab-and-field-data-with-crux","Comparing Lab and Field Data with CrUX",{"path":1432,"title":1433},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci","Performance Budgets and Lighthouse CI",{"path":1435,"title":1436},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Freducing-lighthouse-score-variance-in-ci","Reducing Lighthouse Score Variance in CI",{"path":1438,"title":1439},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Frunning-webpagetest-scripts-against-preview-deploys","Running WebPageTest Scripts Against Preview Deploys",{"path":1441,"title":1442},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fsetting-up-lighthouse-ci-for-a-static-site","Setting Up Lighthouse CI for a Static Site",{"path":1444,"title":1445},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Ftracking-bundle-size-per-pull-request","Tracking Bundle Size per Pull Request",{"path":1447,"title":1448},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fwriting-a-performance-budget-that-fails-builds","Writing a Performance Budget That Fails Builds",{"path":1450,"title":1451},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fauditing-unused-preloads","Auditing Unused Preloads",{"path":1453,"title":1454},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed","Resource Hints and Navigation Speed",{"path":1456,"title":1457},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Finstant-navigation-with-speculation-rules","Instant Navigation with Speculation Rules",{"path":1459,"title":1460},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fpreconnect-vs-dns-prefetch-on-static-sites","Preconnect vs DNS-Prefetch on Static Sites",{"path":1462,"title":1463},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fprefetching-links-in-astro","Prefetching Links in Astro",{"path":1465,"title":1466},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fview-transitions-on-multi-page-static-sites","View Transitions on Multi-Page Static Sites",{"path":1468,"title":1469},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fauditing-third-party-scripts-with-lighthouse","Auditing Third-Party Scripts With Lighthouse",{"path":1471,"title":782},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites",{"path":1473,"title":1474},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Flazy-loading-youtube-embeds-on-static-sites","Lazy-Loading YouTube Embeds on Static Sites",{"path":1476,"title":1088},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Floading-google-tag-manager-without-hurting-inp",{"path":1478,"title":1479},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Frunning-third-party-scripts-in-a-web-worker-with-partytown","Running Third-Party Scripts in a Web Worker with Partytown",{"path":1481,"title":1095},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fself-hosting-analytics-to-cut-third-party-requests",{"path":1483,"title":1484},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fautomating-eleventy-deployments-with-cloudflare-pages","Automating Eleventy Deployments on Cloudflare Pages",{"path":1486,"title":1487},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fconfiguring-redirects-on-cloudflare-pages","Configuring Redirects on Cloudflare Pages",{"path":1489,"title":1490},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fcustom-domains-and-tls-on-cloudflare-pages","Custom Domains and TLS on Cloudflare Pages",{"path":1492,"title":1493},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fdeploying-hugo-to-cloudflare-pages-and-workers","Deploying Hugo to Cloudflare Pages and Workers",{"path":1495,"title":1496},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup","Cloudflare Pages Edge Caching Setup",{"path":1498,"title":1499},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fmigrating-from-cloudflare-pages-to-workers-static-assets","Migrating from Cloudflare Pages to Workers Static Assets",{"path":1501,"title":1502},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fchecking-links-in-pull-requests","Checking Links in Pull Requests",{"path":1504,"title":1505},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fdocs-as-code-review-workflow-for-writers","Docs-as-Code Review Workflow for Writers",{"path":1507,"title":1508},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Feditorial-checks-with-vale-in-ci","Editorial Checks with Vale in CI",{"path":1510,"title":1511},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams","Content Workflows for Documentation Teams",{"path":1513,"title":1514},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fscheduling-content-publication-with-cron-triggered-builds","Scheduling Content Publication With Cron-Triggered Builds",{"path":1516,"title":1517},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fwiring-a-headless-cms-to-a-static-build","Wiring a Headless CMS to a Static Build",{"path":1519,"title":1520},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fbuilding-astro-sites-with-github-actions","Building Astro Sites with GitHub Actions",{"path":1522,"title":1523},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fcaching-node-modules-in-github-actions-for-faster-ssg-builds","Caching node_modules in GitHub Actions",{"path":1525,"title":1526},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fdeploying-to-github-pages-with-actions","Deploying to GitHub Pages with Actions",{"path":1528,"title":1529},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fdeploying-to-multiple-environments-from-one-workflow","Deploying to Multiple Environments From One Workflow",{"path":1531,"title":1532},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fhow-to-set-up-github-actions-for-hugo-deployments","GitHub Actions for Hugo Deployments",{"path":1534,"title":1535},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds","GitHub Actions for Automated SSG Builds",{"path":1537,"title":1538},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fmatrix-builds-for-multi-site-monorepos","Matrix Builds for Multi-Site Monorepos",{"path":1540,"title":1541},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fcaching-hugo-builds-in-github-actions","Caching Hugo Builds in GitHub Actions",{"path":1543,"title":1544},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fenabling-incremental-builds-in-eleventy","Enabling Incremental Builds in Eleventy",{"path":1546,"title":1547},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fincremental-builds-in-astro-with-the-content-layer","Incremental Builds in Astro with the Content Layer",{"path":1549,"title":1550},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs","Incremental Builds and Build Caching for SSGs",{"path":1552,"title":1553},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fmeasuring-build-time-regressions-in-ci","Measuring Build-Time Regressions in CI",{"path":1555,"title":1556},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fremote-caching-with-turborepo-for-ssg-monorepos","Remote Caching with Turborepo for SSG Monorepos",{"path":1558,"title":1559},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fsharing-build-cache-across-ci-runners","Sharing Build Cache Across CI Runners",{"path":1561,"title":1562},"\u002Fproduction-ready-deployment-cicd-workflows","Production-Ready Deployment & CI\u002FCD for SSGs",{"path":1564,"title":1565},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Falerting-on-cache-hit-ratio-drops","Alerting on Cache Hit Ratio Drops",{"path":1567,"title":1568},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Fbuilding-a-core-web-vitals-dashboard-from-rum-data","Building a Core Web Vitals Dashboard from RUM Data",{"path":1570,"title":1571},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Fcrawling-for-broken-links-on-a-schedule","Crawling for Broken Links on a Schedule",{"path":1573,"title":1574},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production","Monitoring Static Sites in Production",{"path":1576,"title":1577},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Flogging-404s-at-the-edge","Logging 404s at the Edge",{"path":1579,"title":1580},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Fuptime-and-synthetic-checks-for-static-sites","Uptime and Synthetic Checks for Static Sites",{"path":1582,"title":1583},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fconfiguring-vercel-for-hugo-and-eleventy","Configuring Vercel for Hugo and Eleventy",{"path":1585,"title":1586},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies","Netlify vs Vercel Deployment Strategies",{"path":1588,"title":1589},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-build-hooks-for-content-updates","Netlify Build Hooks for Content Updates",{"path":1591,"title":1592},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-redirects-and-rewrites-for-static-sites","Netlify Redirects and Rewrites for Static Sites",{"path":1594,"title":1595},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fsetting-up-deploy-previews-on-netlify-for-every-pull-request","Netlify Deploy Previews for Every Pull Request",{"path":1597,"title":1598},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fvercel-isr-vs-static-generation-for-ssgs","Vercel ISR vs Static Generation for SSGs",{"path":1600,"title":1601},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fautomating-preview-deploy-pipelines-with-github-actions","Automating Preview Deploy Pipelines with GitHub Actions",{"path":1603,"title":1604},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fcleaning-up-stale-preview-deployments","Cleaning Up Stale Preview Deployments",{"path":1606,"title":1607},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests","Preview Environments for Pull Requests",{"path":1609,"title":1610},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fpassword-protecting-preview-deployments","Password-Protecting Preview Deployments",{"path":1612,"title":1613},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fpreviewing-headless-cms-drafts","Previewing Headless CMS Drafts",{"path":1615,"title":1616},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fvisual-regression-testing-on-preview-deploys","Visual Regression Testing on Preview Deploys",{"path":1618,"title":1619},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fatomic-deploys-vs-incremental-uploads","Atomic Deploys vs Incremental Uploads",{"path":1621,"title":1622},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fcanary-releases-for-static-sites","Canary Releases for Static Sites",{"path":1624,"title":1625},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Ffeature-flags-on-static-sites","Feature Flags on Static Sites",{"path":1627,"title":1628},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites","Rollbacks and Deploy Safety for Static Sites",{"path":1630,"title":1631},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-a-bad-static-deploy-in-under-a-minute","Rolling Back a Bad Static Deploy in Under a Minute",{"path":1633,"title":1634},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frunning-smoke-tests-against-a-preview-url","Running Smoke Tests Against a Preview URL",{"path":1636,"title":1637},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fauditing-npm-dependencies-in-ssg-pipelines","Auditing npm Dependencies in SSG Pipelines",{"path":1639,"title":1640},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fenabling-hsts-and-preload-safely","Enabling HSTS and Preload Safely",{"path":1642,"title":1643},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fhash-based-csp-for-inline-scripts-in-astro","Hash-Based CSP for Inline Scripts in Astro",{"path":1645,"title":1646},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites","Security Headers and Hardening for Static Sites",{"path":1648,"title":1649},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsecuring-deploy-credentials-with-github-oidc","Securing Deploy Credentials with GitHub OIDC",{"path":1651,"title":1652},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsubresource-integrity-for-third-party-assets","Subresource Integrity for Third-Party Assets",{"path":1654,"title":1655},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fwriting-a-content-security-policy-for-a-static-site","Writing a Content Security Policy for a Static Site",{"path":1657,"title":1658},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fclean-urls-and-trailing-slashes-on-s3","Clean URLs and Trailing Slashes on S3",{"path":1660,"title":1661},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fcloudfront-functions-for-redirects","CloudFront Functions for Redirects",{"path":1663,"title":1664},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fdeploying-a-static-site-to-s3-and-cloudfront","Deploying a Static Site to S3 and CloudFront",{"path":1666,"title":1667},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites","Self-Hosting Static Sites on S3, Nginx and Caddy",{"path":1669,"title":1670},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-caddy","Serving a Static Site with Caddy",{"path":1672,"title":1673},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-nginx","Serving a Static Site with Nginx",{"path":1675,"title":1676},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fzero-downtime-deploys-with-symlink-swaps","Zero-Downtime Deploys with Symlink Swaps",{"path":1678,"title":1679},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fadding-a-contact-form-with-cloudflare-workers","Adding a Contact Form with Cloudflare Workers",{"path":1681,"title":1682},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fhandling-form-submissions-on-a-static-site","Handling Form Submissions on a Static Site",{"path":1684,"title":1685},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites","Serverless Functions for Static Sites",{"path":1687,"title":1688},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fnetlify-functions-vs-cloudflare-workers","Netlify Functions vs Cloudflare Workers",{"path":1690,"title":1691},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fprotecting-a-static-site-behind-authentication","Protecting a Static Site Behind Authentication",{"path":1693,"title":1694},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fproxying-third-party-apis-from-an-edge-function","Proxying Third-Party APIs from an Edge Function",1789722847094]