[{"data":1,"prerenderedAt":1305},["ShallowReactive",2],{"content:\u002Fimage-media-optimization":3,"surroundings:\u002Fimage-media-optimization":1296},{"id":4,"title":5,"body":6,"description":1278,"extension":1279,"meta":1280,"navigation":1289,"path":1290,"seo":1291,"stem":1294,"__hash__":1295},"content\u002Fimage-media-optimization\u002Findex.md","Image & Media Optimization",{"type":7,"value":8,"toc":1260},"minimark",[9,14,18,42,182,187,195,198,226,229,233,236,256,286,289,293,316,326,333,345,349,352,378,388,413,417,423,430,441,444,448,458,578,599,606,761,782,786,939,958,962,1042,1058,1060,1064,1136,1138,1142,1154,1166,1184,1201,1216,1218,1222,1245,1250,1253,1256],[10,11,13],"h1",{"id":12},"image-media-optimization-engineering-the-delivery-pipeline-for-lcp-and-cls","Image & Media Optimization: Engineering the Delivery Pipeline for LCP and CLS",[15,16,17],"p",{},"On the median web page, images are the single largest byte contributor and the most frequent Largest Contentful Paint (LCP) element. That makes image delivery the highest-leverage surface for hitting the production thresholds that matter: LCP under 2.5 seconds and Cumulative Layout Shift (CLS) below 0.1 at the field 75th percentile. A hero image that is over-sized, served in JPEG, fetched at default priority, and lazy-loaded by mistake can single-handedly push LCP past 4 seconds while injecting layout shift on top of it.",[15,19,20,21,26,27,31,32,36,37,41],{},"The fix is not a single setting. It is an end-to-end pipeline: the right pixels (responsive sizing via ",[22,23,25],"a",{"href":24},"\u002Fimage-media-optimization\u002Fresponsive-images-with-srcset-and-sizes\u002F","srcset and sizes","), in the right format (AVIF or WebP with ",[22,28,30],{"href":29},"\u002Fimage-media-optimization\u002Fserving-avif-and-webp-with-fallbacks\u002F","graceful fallbacks","), delivered from the right place with the right priority (",[22,33,35],{"href":34},"\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority\u002F","image CDNs and fetchpriority","), at the right time (",[22,38,40],{"href":39},"\u002Fimage-media-optimization\u002Flazy-loading-images-without-hurting-lcp\u002F","lazy-loading that never touches the LCP candidate","). This guide walks the full path from origin asset to painted pixel, frames every stage against a measurable threshold, and gives you copy-paste reference implementations with explicit trade-offs.",[15,43,44],{},[45,46,53,54,53,58,53,62,53,72,53,79,53,86,53,89,53,92,53,98,53,102,53,107,53,112,53,116,53,119,53,123,53,126,53,130,53,133,53,137,53,140,53,146,53,149,53,152,53,155,53,160,53,165,53,170,53,174,53,178,53],"svg",{"xmlns":47,"viewBox":48,"width":49,"role":50,"ariaLabel":51,"style":52},"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","0 0 760 320","100%","img","Image delivery pipeline from origin asset through CDN transform, format negotiation, priority hints, to decode and paint","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:#001d3d"," ",[55,56,57],"title",{},"Image delivery pipeline",[59,60,61],"desc",{},"Five stages from the origin asset to the painted pixel: CDN transform, format negotiation, priority hints, decode and paint, each with the metric it governs.",[63,64],"rect",{"x":65,"y":65,"width":66,"height":67,"rx":68,"fill":69,"stroke":70,"style":71},"1","758","318","10","none","currentColor","stroke-opacity:0.18",[73,74,78],"text",{"x":75,"y":76,"fill":70,"style":77},"24","38","font-size:18px;font-weight:700","Image delivery pipeline (LCP budget 2.5s, CLS budget 0.1)",[63,80],{"x":75,"y":81,"width":82,"height":81,"rx":83,"fill":84,"stroke":84,"style":85},"64","132","6","#0466c8","fill-opacity:0.12",[63,87],{"x":88,"y":81,"width":82,"height":81,"rx":83,"fill":84,"stroke":84,"style":85},"170",[63,90],{"x":91,"y":81,"width":82,"height":81,"rx":83,"fill":84,"stroke":84,"style":85},"316",[63,93],{"x":94,"y":81,"width":82,"height":81,"rx":83,"fill":95,"stroke":96,"style":97},"462","#ffc300","#b8860b","fill-opacity:0.22",[63,99],{"x":100,"y":81,"width":101,"height":81,"rx":83,"fill":84,"stroke":84,"style":85},"608","128",[73,103,106],{"x":104,"y":104,"fill":70,"style":105},"90","font-size:13px;font-weight:600;text-anchor:middle","Origin asset",[73,108,111],{"x":104,"y":109,"fill":70,"style":110},"110","font-size:12px;text-anchor:middle","master, lossless",[73,113,115],{"x":114,"y":104,"fill":70,"style":105},"236","CDN transform",[73,117,118],{"x":114,"y":109,"fill":70,"style":110},"resize + recompress",[73,120,122],{"x":121,"y":104,"fill":70,"style":105},"382","Format negotiation",[73,124,125],{"x":121,"y":109,"fill":70,"style":110},"AVIF \u002F WebP \u002F JPEG",[73,127,129],{"x":128,"y":104,"fill":70,"style":105},"528","Priority hints",[73,131,132],{"x":128,"y":109,"fill":70,"style":110},"fetchpriority=high",[73,134,136],{"x":135,"y":104,"fill":70,"style":105},"672","Decode + paint",[73,138,139],{"x":135,"y":109,"fill":70,"style":110},"LCP recorded",[141,142],"line",{"x1":143,"y1":144,"x2":88,"y2":144,"stroke":70,"style":145},"156","96","stroke-opacity:0.45",[141,147],{"x1":148,"y1":144,"x2":91,"y2":144,"stroke":70,"style":145},"302",[141,150],{"x1":151,"y1":144,"x2":94,"y2":144,"stroke":70,"style":145},"448",[141,153],{"x1":154,"y1":144,"x2":100,"y2":144,"stroke":70,"style":145},"594",[141,156],{"x1":75,"y1":157,"x2":158,"y2":157,"stroke":70,"style":159},"166","736","stroke-opacity:0.3",[73,161,164],{"x":75,"y":162,"fill":70,"style":163},"196","font-size:14px;font-weight:600","Stage owners of the metric",[73,166,169],{"x":75,"y":167,"fill":70,"style":168},"222","font-size:13px","Transform + format cut bytes, shorten LCP load",[73,171,173],{"x":75,"y":172,"fill":70,"style":168},"248","Priority hints cut load delay; dimensions hold CLS",[73,175,177],{"x":75,"y":176,"fill":70,"style":168},"274","Decode is main-thread time; big images stall paint",[73,179,181],{"x":75,"y":180,"fill":70,"style":168},"300","Field p75 ships; the lab waterfall locates it",[183,184,186],"h2",{"id":185},"diagnostic-overview-locating-the-image-that-owns-your-lcp","Diagnostic Overview: Locating the Image That Owns Your LCP",[15,188,189,190,194],{},"Before changing anything, identify which image is the LCP element and which pipeline stage is slow. The field 75th percentile (p75) is the boundary that ships, but the lab waterfall is where you find the bottleneck. Open the Performance panel, reload, and read the LCP marker; then expand the network request for that resource to break LCP into its four phases. For the full timeline workflow, see ",[22,191,193],{"href":192},"\u002Fcore-web-vitals-measurement\u002Fmeasuring-lcp-with-chrome-devtools\u002F","measuring LCP with Chrome DevTools",".",[15,196,197],{},"The image LCP almost always decomposes into one dominant phase, and each points at a different stage of the pipeline:",[199,200,201,214,220],"ul",{},[202,203,204,208,209,213],"li",{},[205,206,207],"strong",{},"Load delay"," (time from First Contentful Paint to when the image starts downloading) → a priority or discovery problem. The image was discovered late, queued behind lower-value requests, or marked ",[210,211,212],"code",{},"loading=\"lazy\"",". Owned by priority hints.",[202,215,216,219],{},[205,217,218],{},"Load time"," (download duration) → a bytes problem. The image is too large in pixels, in the wrong format, or fetched from a slow origin. Owned by responsive sizing, format, and CDN transform.",[202,221,222,225],{},[205,223,224],{},"Render delay"," (download complete to paint) → a decode or main-thread problem. The decode is competing with hydration, or the image is held behind render-blocking CSS\u002FJS.",[15,227,228],{},"Cross-reference the lab finding against field percentiles. If p50 is healthy but p95 is failing, the problem is network and device variance — push harder on byte reduction. If p75 itself fails uniformly, the problem is structural (wrong priority or wrong format for everyone). Prioritize the dominant phase first; fixing render delay does nothing if 1.8s of your budget is load time.",[183,230,232],{"id":231},"architecture-1-right-pixels-responsive-sizing-and-the-byte-budget","Architecture 1: Right Pixels — Responsive Sizing and the Byte Budget",[15,234,235],{},"The cheapest byte is the one you never send. Most LCP load-time regressions come from shipping a 2400px-wide master to a 390px phone viewport — a payload roughly 38 times larger than required. The job of this stage is to deliver an image whose intrinsic pixels match the device's CSS layout size multiplied by its device pixel ratio (DPR), and no more.",[15,237,238,241,242,245,246,248,249,252,253,255],{},[22,239,240],{"href":24},"Responsive images with srcset and sizes"," is the native mechanism for this. You provide a set of width-descriptor candidates and a ",[210,243,244],{},"sizes"," attribute describing the rendered width at each breakpoint; the browser picks the smallest candidate that still covers the slot at the current DPR. The most common failure is an inaccurate ",[210,247,244],{}," value — if you declare ",[210,250,251],{},"100vw"," but the image actually renders in a 600px column, the browser over-fetches every time. ",[210,254,244],{}," must track your CSS layout, so it has to be revisited whenever the layout changes.",[15,257,258,259,262,263,262,266,269,270,272,273,262,276,279,280,282,283,285],{},"There are two descriptor strategies. Width descriptors (",[210,260,261],{},"480w",", ",[210,264,265],{},"960w",[210,267,268],{},"1440w",") with ",[210,271,244],{}," let the browser solve for DPR automatically and are the correct default for layout-driven images. Pixel-density descriptors (",[210,274,275],{},"1x",[210,277,278],{},"2x",") are simpler but only correct for fixed-size images (icons, avatars) where the CSS dimensions never change. Mixing them or omitting ",[210,281,244],{}," with width descriptors forces the browser to assume ",[210,284,251],{},", defeating the purpose.",[15,287,288],{},"Generate a sensible ladder of candidate widths — typically 320, 480, 640, 768, 960, 1280, 1920 — rather than one per device. A 5–8 step ladder captures nearly all the savings; finer granularity bloats the build and the CDN cache key with negligible benefit. Pair this with high-DPI correctness so the same markup serves crisp pixels on retina screens without doubling bytes for everyone.",[183,290,292],{"id":291},"architecture-2-right-format-and-source-avif-webp-and-cdn-transforms","Architecture 2: Right Format and Source — AVIF, WebP, and CDN Transforms",[15,294,295,296,299,300,303,304,307,308,311,312,315],{},"Format is the second-largest lever after sizing. For the same perceptual quality, AVIF typically lands 30–50% smaller than JPEG and 15–30% smaller than WebP; WebP itself runs 25–35% under JPEG. On a 200KB hero JPEG, switching to AVIF can reclaim ~100KB of LCP load time on its own. The mechanics of ",[22,297,298],{"href":29},"serving AVIF and WebP with fallbacks"," rely on content negotiation: either the ",[210,301,302],{},"\u003Cpicture>"," element with ",[210,305,306],{},"type","-gated ",[210,309,310],{},"\u003Csource>"," tags, or an image CDN reading the ",[210,313,314],{},"Accept"," request header and returning the best format the client advertises.",[15,317,318,319,321,322,325],{},"The two negotiation paths trade build complexity against runtime flexibility. The ",[210,320,302],{}," element is fully declarative and works without a CDN, but you must pre-generate and reference every format\u002Fsize combination yourself, and the markup grows quickly. Header-based negotiation through an ",[22,323,324],{"href":34},"image CDN"," collapses the markup to a single URL with query parameters and lets the edge decide, but it adds a vendor dependency and a per-image transform cost on cold cache.",[15,327,328,329,332],{},"AVIF is not free. Its encode is dramatically more CPU-intensive than JPEG or WebP, and its ",[205,330,331],{},"decode"," can also be heavier at large resolutions — relevant because decode happens on the path to paint and shows up as LCP render delay on low-end devices. The practical rule: serve AVIF for large content images where byte savings dominate, but benchmark decode on a representative low-end Android before assuming it is a universal win. For full-format selection guidance, the AVIF-versus-WebP decision comes down to browser support floor, encode-time budget, and whether your CDN does the work for you.",[15,334,335,336,340,341,344],{},"Whichever format you serve, the asset must come off a CDN edge close to the user, not your origin. Pair the transform layer with long-lived, immutable caching so a given variant is computed once and served from the edge thereafter; see ",[22,337,339],{"href":338},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fcdn-edge-caching-configuration\u002F","CDN edge caching configuration"," for the surrogate-key and ",[210,342,343],{},"Cache-Control"," setup that keeps transform cost off the critical path. Include the format and width in the cache key so AVIF and JPEG variants do not collide.",[183,346,348],{"id":347},"architecture-3-right-time-and-visual-stability-priority-lazy-loading-and-cls","Architecture 3: Right Time and Visual Stability — Priority, Lazy-Loading, and CLS",[15,350,351],{},"The final stage is scheduling and stability: making sure the LCP image is discovered early and fetched first, that off-screen images do not steal bandwidth, and that no image shifts the layout.",[15,353,354,355,358,359,362,363,366,367,370,371,374,375,194],{},"Browsers assign images a low initial fetch priority by default, because most images are below the fold. For the LCP image that default is actively harmful — it queues your most important pixels behind scripts and stylesheets. Apply ",[210,356,357],{},"fetchpriority=\"high\""," to the LCP ",[210,360,361],{},"\u003Cimg>"," so the browser promotes it immediately; this is the single highest-impact one-line change for image LCP and is covered in depth under ",[22,364,365],{"href":34},"using fetchpriority to prioritize the LCP image",". For an LCP image that the preload scanner cannot find early (CSS background, or injected by JS), add a ",[210,368,369],{},"\u003Clink rel=\"preload\" as=\"image\" fetchpriority=\"high\">"," with matching ",[210,372,373],{},"imagesrcset","\u002F",[210,376,377],{},"imagesizes",[15,379,380,381,383,384,387],{},"Lazy-loading is the inverse lever and the most common self-inflicted LCP wound. Native ",[210,382,212],{}," is correct for everything below the fold, but applying it to the LCP image — or to anything in the initial viewport — adds load delay because the browser defers the fetch until layout confirms visibility. The rule is absolute: never lazy-load the LCP candidate or any above-the-fold image. ",[22,385,386],{"href":39},"Lazy-loading images without hurting LCP"," covers how to draw the fold boundary reliably, including why the native heuristic and a hand-rolled IntersectionObserver behave differently for images near the viewport edge.",[15,389,390,391,394,395,398,399,402,403,394,405,408,409,194],{},"Visual stability is governed by dimensions. Every layout shift from media comes from the same root cause: the browser reserved no space before the image arrived, so surrounding content jumps when it paints. Always set ",[210,392,393],{},"width"," and ",[210,396,397],{},"height"," attributes (or the modern ",[210,400,401],{},"aspect-ratio"," CSS) on every ",[210,404,361],{},[210,406,407],{},"\u003Cvideo>","; the browser then reserves the correct box from first layout and the image fills it with zero shift. This single discipline eliminates most image-driven CLS. For the broader stability model and the field-debugging workflow, see ",[22,410,412],{"href":411},"\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002F","reducing Cumulative Layout Shift (CLS)",[183,414,416],{"id":415},"monitoring-ci-holding-the-pipeline-to-its-budget","Monitoring & CI: Holding the Pipeline to Its Budget",[15,418,419,420,422],{},"Image regressions creep in silently — a designer swaps a 90KB hero for a 600KB one, or someone adds ",[210,421,212],{}," to a template that renders above the fold. Field monitoring catches the user-facing damage; CI budgets catch it before deploy.",[15,424,425,426,429],{},"In the field, attribute LCP to its element and phase. The ",[210,427,428],{},"web-vitals"," library exposes LCP attribution, including the element selector, the resource URL, and the load-delay\u002Fload-time\u002Frender-delay breakdown. Beacon that attribution to your RUM endpoint so you can answer \"which image regressed and which phase grew\" without guessing. Watch p75 by template, not site-wide; a single bad product-page hero hides in an aggregate average.",[15,431,432,433,436,437,440],{},"In CI, assert two independent budgets. First, a Lighthouse CI numeric assertion on ",[210,434,435],{},"largest-contentful-paint"," so any image change that pushes LCP past 2500ms blocks the merge. Second, a per-image transfer-size budget (via Lighthouse ",[210,438,439],{},"resource-summary"," or a bundle\u002Fasset budget tool) so an oversized asset fails even if a fast CI runner masks its LCP impact. Run Lighthouse under throttled CPU (4x) and a slow network profile so the image byte cost is visible — on an unthrottled runner a 600KB hero downloads in milliseconds and the regression hides.",[442,443],"hr",{},[183,445,447],{"id":446},"reference-implementations","Reference Implementations",[449,450,452,453,455,456],"h3",{"id":451},"responsive-img-with-width-descriptors-and-accurate-sizes","Responsive ",[210,454,361],{}," with width descriptors and accurate ",[210,457,244],{},[459,460,465],"pre",{"className":461,"code":462,"language":463,"meta":464,"style":464},"language-html shiki shiki-themes github-light-high-contrast github-light-high-contrast github-light-high-contrast","\u003Cimg\n  src=\"\u002Fimg\u002Fhero-960.jpg\"\n  srcset=\"\u002Fimg\u002Fhero-480.avif 480w, \u002Fimg\u002Fhero-960.avif 960w, \u002Fimg\u002Fhero-1440.avif 1440w\"\n  sizes=\"(max-width: 600px) 100vw, 600px\"\n  width=\"1440\" height=\"810\"\n  fetchpriority=\"high\"\n  alt=\"Quarterly revenue dashboard\">\n\u003C!-- trade-off: fetchpriority=\"high\" and the omission of loading=\"lazy\" are correct ONLY\n     for the LCP\u002Fabove-the-fold image. Apply this template below the fold and you waste\n     bandwidth on off-screen pixels and starve the real LCP element. -->\n","html","",[210,466,467,479,493,504,515,534,545,559,566,572],{"__ignoreMap":464},[468,469,471,475],"span",{"class":141,"line":470},1,[468,472,474],{"class":473},"syybb","\u003C",[468,476,478],{"class":477},"s-fAs","img\n",[468,480,482,486,489],{"class":141,"line":481},2,[468,483,485],{"class":484},"sf6mN","  src",[468,487,488],{"class":473},"=",[468,490,492],{"class":491},"s-_DF","\"\u002Fimg\u002Fhero-960.jpg\"\n",[468,494,496,499,501],{"class":141,"line":495},3,[468,497,498],{"class":484},"  srcset",[468,500,488],{"class":473},[468,502,503],{"class":491},"\"\u002Fimg\u002Fhero-480.avif 480w, \u002Fimg\u002Fhero-960.avif 960w, \u002Fimg\u002Fhero-1440.avif 1440w\"\n",[468,505,507,510,512],{"class":141,"line":506},4,[468,508,509],{"class":484},"  sizes",[468,511,488],{"class":473},[468,513,514],{"class":491},"\"(max-width: 600px) 100vw, 600px\"\n",[468,516,518,521,523,526,529,531],{"class":141,"line":517},5,[468,519,520],{"class":484},"  width",[468,522,488],{"class":473},[468,524,525],{"class":491},"\"1440\"",[468,527,528],{"class":484}," height",[468,530,488],{"class":473},[468,532,533],{"class":491},"\"810\"\n",[468,535,537,540,542],{"class":141,"line":536},6,[468,538,539],{"class":484},"  fetchpriority",[468,541,488],{"class":473},[468,543,544],{"class":491},"\"high\"\n",[468,546,548,551,553,556],{"class":141,"line":547},7,[468,549,550],{"class":484},"  alt",[468,552,488],{"class":473},[468,554,555],{"class":491},"\"Quarterly revenue dashboard\"",[468,557,558],{"class":473},">\n",[468,560,562],{"class":141,"line":561},8,[468,563,565],{"class":564},"sIIH1","\u003C!-- trade-off: fetchpriority=\"high\" and the omission of loading=\"lazy\" are correct ONLY\n",[468,567,569],{"class":141,"line":568},9,[468,570,571],{"class":564},"     for the LCP\u002Fabove-the-fold image. Apply this template below the fold and you waste\n",[468,573,575],{"class":141,"line":574},10,[468,576,577],{"class":564},"     bandwidth on off-screen pixels and starve the real LCP element. -->\n",[199,579,580,588],{},[202,581,582,53,585,587],{},[205,583,584],{},"Config:",[210,586,244],{}," must mirror the CSS — here the image is full-width up to 600px, then capped at 600px.",[202,589,590,593,594,374,596,598],{},[205,591,592],{},"Outcome:"," Phones fetch the 480w AVIF (~25KB) instead of the 1440w master, cutting LCP load time substantially while ",[210,595,393],{},[210,597,397],{}," hold CLS at 0.",[449,600,602,603,605],{"id":601},"format-negotiation-with-picture-and-a-jpeg-fallback","Format negotiation with ",[210,604,302],{}," and a JPEG fallback",[459,607,609],{"className":461,"code":608,"language":463,"meta":464,"style":464},"\u003Cpicture>\n  \u003Csource type=\"image\u002Favif\" srcset=\"\u002Fimg\u002Fcard-480.avif 480w, \u002Fimg\u002Fcard-960.avif 960w\" sizes=\"(max-width:600px) 100vw, 480px\">\n  \u003Csource type=\"image\u002Fwebp\" srcset=\"\u002Fimg\u002Fcard-480.webp 480w, \u002Fimg\u002Fcard-960.webp 960w\" sizes=\"(max-width:600px) 100vw, 480px\">\n  \u003Cimg src=\"\u002Fimg\u002Fcard-960.jpg\" width=\"960\" height=\"540\" loading=\"lazy\" decoding=\"async\" alt=\"Feature card\">\n\u003C\u002Fpicture>\n\u003C!-- trade-off: declarative \u003Cpicture> needs no CDN but forces you to pre-generate and list\n     every format x width. Past ~3 images this markup is unmaintainable — switch to a CDN\n     that negotiates on the Accept header and collapses this to one URL. -->\n",[210,610,611,620,654,682,737,746,751,756],{"__ignoreMap":464},[468,612,613,615,618],{"class":141,"line":470},[468,614,474],{"class":473},[468,616,617],{"class":477},"picture",[468,619,558],{"class":473},[468,621,622,625,628,631,633,636,639,641,644,647,649,652],{"class":141,"line":481},[468,623,624],{"class":473},"  \u003C",[468,626,627],{"class":477},"source",[468,629,630],{"class":484}," type",[468,632,488],{"class":473},[468,634,635],{"class":491},"\"image\u002Favif\"",[468,637,638],{"class":484}," srcset",[468,640,488],{"class":473},[468,642,643],{"class":491},"\"\u002Fimg\u002Fcard-480.avif 480w, \u002Fimg\u002Fcard-960.avif 960w\"",[468,645,646],{"class":484}," sizes",[468,648,488],{"class":473},[468,650,651],{"class":491},"\"(max-width:600px) 100vw, 480px\"",[468,653,558],{"class":473},[468,655,656,658,660,662,664,667,669,671,674,676,678,680],{"class":141,"line":495},[468,657,624],{"class":473},[468,659,627],{"class":477},[468,661,630],{"class":484},[468,663,488],{"class":473},[468,665,666],{"class":491},"\"image\u002Fwebp\"",[468,668,638],{"class":484},[468,670,488],{"class":473},[468,672,673],{"class":491},"\"\u002Fimg\u002Fcard-480.webp 480w, \u002Fimg\u002Fcard-960.webp 960w\"",[468,675,646],{"class":484},[468,677,488],{"class":473},[468,679,651],{"class":491},[468,681,558],{"class":473},[468,683,684,686,688,691,693,696,699,701,704,706,708,711,714,716,719,722,724,727,730,732,735],{"class":141,"line":506},[468,685,624],{"class":473},[468,687,50],{"class":477},[468,689,690],{"class":484}," src",[468,692,488],{"class":473},[468,694,695],{"class":491},"\"\u002Fimg\u002Fcard-960.jpg\"",[468,697,698],{"class":484}," width",[468,700,488],{"class":473},[468,702,703],{"class":491},"\"960\"",[468,705,528],{"class":484},[468,707,488],{"class":473},[468,709,710],{"class":491},"\"540\"",[468,712,713],{"class":484}," loading",[468,715,488],{"class":473},[468,717,718],{"class":491},"\"lazy\"",[468,720,721],{"class":484}," decoding",[468,723,488],{"class":473},[468,725,726],{"class":491},"\"async\"",[468,728,729],{"class":484}," alt",[468,731,488],{"class":473},[468,733,734],{"class":491},"\"Feature card\"",[468,736,558],{"class":473},[468,738,739,742,744],{"class":141,"line":517},[468,740,741],{"class":473},"\u003C\u002F",[468,743,617],{"class":477},[468,745,558],{"class":473},[468,747,748],{"class":141,"line":536},[468,749,750],{"class":564},"\u003C!-- trade-off: declarative \u003Cpicture> needs no CDN but forces you to pre-generate and list\n",[468,752,753],{"class":141,"line":547},[468,754,755],{"class":564},"     every format x width. Past ~3 images this markup is unmaintainable — switch to a CDN\n",[468,757,758],{"class":141,"line":561},[468,759,760],{"class":564},"     that negotiates on the Accept header and collapses this to one URL. -->\n",[199,762,763,777],{},[202,764,765,767,768,770,771,773,774,776],{},[205,766,584],{}," Browsers pick the first ",[210,769,310],{}," whose ",[210,772,306],{}," they support; older engines fall through to the ",[210,775,361],{}," JPEG.",[202,778,779,781],{},[205,780,592],{}," AVIF\u002FWebP-capable clients get the small variant; the fallback guarantees an image everywhere.",[449,783,785],{"id":784},"image-cdn-url-with-accept-based-negotiation-and-immutable-caching","Image CDN URL with Accept-based negotiation and immutable caching",[459,787,791],{"className":788,"code":789,"language":790,"meta":464,"style":464},"language-javascript shiki shiki-themes github-light-high-contrast github-light-high-contrast github-light-high-contrast","\u002F\u002F Build a transform URL: resize + auto-format, let the edge read the Accept header.\nfunction cdnImage(path, width) {\n  const params = new URLSearchParams({\n    w: String(width),\n    q: '70',         \u002F\u002F quality 70 is the visual break-even for most photos\n    format: 'auto'   \u002F\u002F edge returns AVIF > WebP > JPEG per client support\n  });\n  return `https:\u002F\u002Fimg.example.com\u002F${path}?${params}`;\n}\n\u002F\u002F Edge response headers (set at the CDN, not the browser):\n\u002F\u002F   Cache-Control: public, max-age=31536000, immutable\n\u002F\u002F   Vary: Accept   \u002F\u002F trade-off: REQUIRED so AVIF\u002FJPEG variants don't cross-serve, but it\n\u002F\u002F                  \u002F\u002F fragments shared caches per Accept value — keep Accept normalized at the edge.\n","javascript",[210,792,793,798,822,842,853,867,878,883,905,910,915,921,930],{"__ignoreMap":464},[468,794,795],{"class":141,"line":470},[468,796,797],{"class":564},"\u002F\u002F Build a transform URL: resize + auto-format, let the edge read the Accept header.\n",[468,799,800,804,808,811,815,817,819],{"class":141,"line":481},[468,801,803],{"class":802},"sP5qI","function",[468,805,807],{"class":806},"ssM3C"," cdnImage",[468,809,810],{"class":473},"(",[468,812,814],{"class":813},"seIZK","path",[468,816,262],{"class":473},[468,818,393],{"class":813},[468,820,821],{"class":473},") {\n",[468,823,824,827,830,833,836,839],{"class":141,"line":495},[468,825,826],{"class":802},"  const",[468,828,829],{"class":484}," params",[468,831,832],{"class":802}," =",[468,834,835],{"class":802}," new",[468,837,838],{"class":806}," URLSearchParams",[468,840,841],{"class":473},"({\n",[468,843,844,847,850],{"class":141,"line":506},[468,845,846],{"class":473},"    w: ",[468,848,849],{"class":806},"String",[468,851,852],{"class":473},"(width),\n",[468,854,855,858,861,864],{"class":141,"line":517},[468,856,857],{"class":473},"    q: ",[468,859,860],{"class":491},"'70'",[468,862,863],{"class":473},",         ",[468,865,866],{"class":564},"\u002F\u002F quality 70 is the visual break-even for most photos\n",[468,868,869,872,875],{"class":141,"line":536},[468,870,871],{"class":473},"    format: ",[468,873,874],{"class":491},"'auto'",[468,876,877],{"class":564},"   \u002F\u002F edge returns AVIF > WebP > JPEG per client support\n",[468,879,880],{"class":141,"line":547},[468,881,882],{"class":473},"  });\n",[468,884,885,888,891,893,896,899,902],{"class":141,"line":561},[468,886,887],{"class":802},"  return",[468,889,890],{"class":491}," `https:\u002F\u002Fimg.example.com\u002F${",[468,892,814],{"class":473},[468,894,895],{"class":491},"}?${",[468,897,898],{"class":473},"params",[468,900,901],{"class":491},"}`",[468,903,904],{"class":473},";\n",[468,906,907],{"class":141,"line":568},[468,908,909],{"class":473},"}\n",[468,911,912],{"class":141,"line":574},[468,913,914],{"class":564},"\u002F\u002F Edge response headers (set at the CDN, not the browser):\n",[468,916,918],{"class":141,"line":917},11,[468,919,920],{"class":564},"\u002F\u002F   Cache-Control: public, max-age=31536000, immutable\n",[468,922,924,927],{"class":141,"line":923},12,[468,925,926],{"class":564},"\u002F\u002F   Vary: Accept",[468,928,929],{"class":564},"   \u002F\u002F trade-off: REQUIRED so AVIF\u002FJPEG variants don't cross-serve, but it\n",[468,931,933,936],{"class":141,"line":932},13,[468,934,935],{"class":564},"\u002F\u002F",[468,937,938],{"class":564},"                  \u002F\u002F fragments shared caches per Accept value — keep Accept normalized at the edge.\n",[199,940,941,953],{},[202,942,943,53,945,948,949,952],{},[205,944,584],{},[210,946,947],{},"format=auto"," removes per-format markup; ",[210,950,951],{},"Vary: Accept"," keeps negotiated variants correct.",[202,954,955,957],{},[205,956,592],{}," One URL serves the optimal format\u002Fsize per device; the transform runs once per variant, then serves from edge cache.",[449,959,961],{"id":960},"preloading-an-lcp-image-the-scanner-cant-see","Preloading an LCP image the scanner can't see",[459,963,965],{"className":461,"code":964,"language":463,"meta":464,"style":464},"\u003C!-- For a CSS background or JS-injected hero: the preload scanner won't find it in time. -->\n\u003Clink rel=\"preload\" as=\"image\"\n      imagesrcset=\"\u002Fimg\u002Fhero-480.avif 480w, \u002Fimg\u002Fhero-1440.avif 1440w\"\n      imagesizes=\"(max-width:600px) 100vw, 600px\"\n      fetchpriority=\"high\">\n\u003C!-- trade-off: preload only when the element is genuinely undiscoverable early. Preloading\n     an \u003Cimg> the scanner already finds double-counts the request and competes with itself;\n     and a preload that never matches a rendered element wastes the whole download. -->\n",[210,966,967,972,995,1005,1015,1027,1032,1037],{"__ignoreMap":464},[468,968,969],{"class":141,"line":470},[468,970,971],{"class":564},"\u003C!-- For a CSS background or JS-injected hero: the preload scanner won't find it in time. -->\n",[468,973,974,976,979,982,984,987,990,992],{"class":141,"line":481},[468,975,474],{"class":473},[468,977,978],{"class":477},"link",[468,980,981],{"class":484}," rel",[468,983,488],{"class":473},[468,985,986],{"class":491},"\"preload\"",[468,988,989],{"class":484}," as",[468,991,488],{"class":473},[468,993,994],{"class":491},"\"image\"\n",[468,996,997,1000,1002],{"class":141,"line":495},[468,998,999],{"class":484},"      imagesrcset",[468,1001,488],{"class":473},[468,1003,1004],{"class":491},"\"\u002Fimg\u002Fhero-480.avif 480w, \u002Fimg\u002Fhero-1440.avif 1440w\"\n",[468,1006,1007,1010,1012],{"class":141,"line":506},[468,1008,1009],{"class":484},"      imagesizes",[468,1011,488],{"class":473},[468,1013,1014],{"class":491},"\"(max-width:600px) 100vw, 600px\"\n",[468,1016,1017,1020,1022,1025],{"class":141,"line":517},[468,1018,1019],{"class":484},"      fetchpriority",[468,1021,488],{"class":473},[468,1023,1024],{"class":491},"\"high\"",[468,1026,558],{"class":473},[468,1028,1029],{"class":141,"line":536},[468,1030,1031],{"class":564},"\u003C!-- trade-off: preload only when the element is genuinely undiscoverable early. Preloading\n",[468,1033,1034],{"class":141,"line":547},[468,1035,1036],{"class":564},"     an \u003Cimg> the scanner already finds double-counts the request and competes with itself;\n",[468,1038,1039],{"class":141,"line":561},[468,1040,1041],{"class":564},"     and a preload that never matches a rendered element wastes the whole download. -->\n",[199,1043,1044,1053],{},[202,1045,1046,53,1048,374,1050,1052],{},[205,1047,584],{},[210,1049,373],{},[210,1051,377],{}," must match the eventual rendered candidate exactly so the preload is reused, not re-fetched.",[202,1054,1055,1057],{},[205,1056,592],{}," Cuts LCP load delay by pulling the hero forward in the request queue before script execution.",[442,1059],{},[183,1061,1063],{"id":1062},"common-pitfalls","Common Pitfalls",[199,1065,1066,1075,1086,1100,1106,1112,1118,1127],{},[202,1067,1068,1071,1072,1074],{},[205,1069,1070],{},"Lazy-loading the LCP image."," A blanket ",[210,1073,212],{}," on an image component applies to the hero too, adding load delay and routinely pushing LCP past 4s. Exempt above-the-fold images explicitly.",[202,1076,1077,1082,1083,1085],{},[205,1078,1079,1080,194],{},"Inaccurate ",[210,1081,244],{}," Declaring ",[210,1084,251],{}," for an image that renders in a fixed column makes the browser over-fetch at every breakpoint, silently inflating LCP load time.",[202,1087,1088,1099],{},[205,1089,1090,1091,374,1093,1095,1096,1098],{},"Missing ",[210,1092,393],{},[210,1094,397],{}," (or ",[210,1097,401],{},")."," Un-dimensioned media reserves no space, so content jumps on paint — the most common source of image CLS above 0.1.",[202,1101,1102,1105],{},[205,1103,1104],{},"Serving the master everywhere."," Shipping one large asset to all viewports wastes bandwidth on phones and is the most frequent load-time regression.",[202,1107,1108,1111],{},[205,1109,1110],{},"Transforming on the origin, not the edge."," Per-request resize\u002Frecompress on the origin adds TTFB and decode latency to the critical path; do the work once and cache the variant at the edge.",[202,1113,1114,1117],{},[205,1115,1116],{},"Ignoring decode cost."," Very large AVIF\u002FJPEG images decode slowly on low-end devices, surfacing as LCP render delay even after download completes. Cap intrinsic dimensions and benchmark decode.",[202,1119,1120,1126],{},[205,1121,1122,1123,1125],{},"Omitting ",[210,1124,951],{}," on CDN responses."," Without it, a cached AVIF can be served to a client that only supports JPEG (or vice versa), producing broken images for a slice of users.",[202,1128,1129,1132,1133,1135],{},[205,1130,1131],{},"Animated GIFs for video."," A looping GIF is megabytes of un-compressible frames. Replace with a muted, looped ",[210,1134,407],{}," (MP4\u002FWebM) for an order-of-magnitude byte reduction.",[442,1137],{},[183,1139,1141],{"id":1140},"faq","FAQ",[1143,1144,1147,1151],"details",{"className":1145},[1146],"faq-item",[1148,1149,1150],"summary",{},"Should I always serve AVIF for the LCP image?",[15,1152,1153],{},"Not blindly. AVIF wins on transfer bytes — often 30–50% under JPEG — which directly shortens LCP load time. But AVIF decode is heavier than JPEG at large resolutions, and decode happens on the path to paint, so on low-end devices a very large AVIF can trade load-time savings for render-delay cost. Serve AVIF with a WebP and JPEG fallback, cap the intrinsic dimensions to what the layout needs, and verify decode time on a representative low-end Android before assuming a net win.",[1143,1155,1157,1160],{"className":1156},[1146],[1148,1158,1159],{},"How do I know which image is my LCP element?",[15,1161,1162,1163,1165],{},"Open the Performance panel in Chrome DevTools, reload, and read the LCP marker on the timeline — it names the element and links to its network request. The ",[210,1164,428],{}," library's LCP attribution exposes the same element selector and resource URL in the field, plus the load-delay\u002Fload-time\u002Frender-delay split. Confirm the lab finding against field p75 before optimizing, so you fix the image that actually fails for users rather than the one that is slow on your laptop.",[1143,1167,1169,1172],{"className":1168},[1146],[1148,1170,1171],{},"Does `fetchpriority=\"high\"` replace preloading the hero image?",[15,1173,1174,1175,1177,1178,1180,1181,1183],{},"For a normal ",[210,1176,361],{}," that the preload scanner can discover in the initial HTML, ",[210,1179,357],{}," is enough and is simpler — it promotes the existing request without adding one. Preload is for images the scanner cannot find early: CSS backgrounds, or images injected by JavaScript after parse. Using both on a discoverable ",[210,1182,361],{}," risks double-counting the request, so pick one based on whether the element is visible to the parser.",[1143,1185,1187,1190],{"className":1186},[1146],[1148,1188,1189],{},"Why is `width` and `height` better than fixing CLS with CSS later?",[15,1191,1192,1193,394,1195,1197,1198,1200],{},"Setting the ",[210,1194,393],{},[210,1196,397],{}," attributes (or ",[210,1199,401],{},") lets the browser compute the correct box during the very first layout pass, before the image bytes arrive, so there is never a shift to fix. Reactive CSS patches run after the shift has already been recorded against your CLS budget. Reserving space up front is the only approach that keeps image CLS at zero rather than merely reducing it.",[1143,1202,1204,1207],{"className":1203},[1146],[1148,1205,1206],{},"How small should I make the candidate width ladder in `srcset`?",[15,1208,1209,1210,1212,1213,1215],{},"Five to eight steps — for example 320, 480, 640, 768, 960, 1280, 1920 — capture nearly all the achievable byte savings. A device-perfect candidate for every screen adds build time and fragments the CDN cache for negligible benefit, since the browser only needs the smallest candidate that covers the slot at the current DPR. Keep the ladder coarse and make sure your ",[210,1211,244],{}," value is accurate; an accurate ",[210,1214,244],{}," matters far more than ladder granularity.",[442,1217],{},[183,1219,1221],{"id":1220},"related","Related",[199,1223,1224,1231,1238],{},[202,1225,1226,1230],{},[22,1227,1229],{"href":1228},"\u002Fcore-web-vitals-measurement\u002F","Core Web Vitals: measurement and optimization"," — the field-versus-lab workflow and RUM setup that tells you whether an image change moved p75.",[202,1232,1233,1237],{},[22,1234,1236],{"href":1235},"\u002Fjavascript-bundle-optimization-code-splitting\u002F","JavaScript bundle optimization and code splitting"," — keep script execution from competing with image decode and stealing render delay from your LCP paint.",[202,1239,1240,1244],{},[22,1241,1243],{"href":1242},"\u002Fadvanced-caching-strategies-cdn-architecture\u002F","Advanced caching strategies and CDN architecture"," — the edge caching and immutable-header model that keeps image transform cost off the critical path.",[1246,1247,1249],"script",{"type":1248},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"Article\",\n  \"headline\": \"Image & Media Optimization: Engineering the Delivery Pipeline for LCP and CLS\",\n  \"description\": \"Production playbook for the image delivery pipeline: responsive sizing, next-gen formats, CDN transforms, priority hints, decode cost, and CLS-safe media.\",\n  \"datePublished\": \"2026-06-18\",\n  \"dateModified\": \"2026-06-18\",\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\u002Fimage-media-optimization\u002F\" }\n}\n",[1246,1251,1252],{"type":1248},"\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\": \"Image & Media Optimization\", \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fimage-media-optimization\u002F\" }\n  ]\n}\n",[1246,1254,1255],{"type":1248},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"FAQPage\",\n  \"mainEntity\": [\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Should I always serve AVIF for the LCP image?\",\n      \"acceptedAnswer\": { \"@type\": \"Answer\", \"text\": \"Not blindly. AVIF wins on transfer bytes, often 30-50% under JPEG, which shortens LCP load time, but AVIF decode is heavier at large resolutions and happens on the path to paint, so on low-end devices a very large AVIF can trade load-time savings for render-delay cost. Serve AVIF with a WebP and JPEG fallback, cap intrinsic dimensions to what the layout needs, and verify decode time on a representative low-end Android.\" }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How do I know which image is my LCP element?\",\n      \"acceptedAnswer\": { \"@type\": \"Answer\", \"text\": \"Open the Performance panel in Chrome DevTools, reload, and read the LCP marker, which names the element and links to its network request. The web-vitals library's LCP attribution exposes the same element selector and resource URL in the field plus the load-delay, load-time, and render-delay split. Confirm the lab finding against field p75 before optimizing.\" }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Does fetchpriority=high replace preloading the hero image?\",\n      \"acceptedAnswer\": { \"@type\": \"Answer\", \"text\": \"For a normal img element the preload scanner can discover in the initial HTML, fetchpriority=high is enough and simpler because it promotes the existing request without adding one. Preload is for images the scanner cannot find early, such as CSS backgrounds or JS-injected images. Using both on a discoverable img risks double-counting the request, so pick one based on whether the element is visible to the parser.\" }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Why is width and height better than fixing CLS with CSS later?\",\n      \"acceptedAnswer\": { \"@type\": \"Answer\", \"text\": \"Setting width and height attributes or aspect-ratio lets the browser compute the correct box during the first layout pass, before the image bytes arrive, so there is never a shift to fix. Reactive CSS patches run after the shift is already recorded against your CLS budget. Reserving space up front keeps image CLS at zero rather than merely reducing it.\" }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How small should I make the candidate width ladder in srcset?\",\n      \"acceptedAnswer\": { \"@type\": \"Answer\", \"text\": \"Five to eight steps, for example 320, 480, 640, 768, 960, 1280, 1920, capture nearly all the achievable byte savings. A device-perfect candidate for every screen adds build time and fragments the CDN cache for negligible benefit, since the browser only needs the smallest candidate that covers the slot at the current DPR. An accurate sizes value matters far more than ladder granularity.\" }\n    }\n  ]\n}\n",[1257,1258,1259],"style",{},"html pre.shiki code .sIIH1, html code.shiki .sIIH1{--shiki-default:#66707B;--shiki-dark:#66707B;--shiki-light:#66707B}html pre.shiki code .sP5qI, html code.shiki .sP5qI{--shiki-default:#A0111F;--shiki-dark:#A0111F;--shiki-light:#A0111F}html pre.shiki code .ssM3C, html code.shiki .ssM3C{--shiki-default:#622CBC;--shiki-dark:#622CBC;--shiki-light:#622CBC}html pre.shiki code .syybb, html code.shiki .syybb{--shiki-default:#0E1116;--shiki-dark:#0E1116;--shiki-light:#0E1116}html pre.shiki code .seIZK, html code.shiki .seIZK{--shiki-default:#702C00;--shiki-dark:#702C00;--shiki-light:#702C00}html pre.shiki code .sf6mN, html code.shiki .sf6mN{--shiki-default:#023B95;--shiki-dark:#023B95;--shiki-light:#023B95}html pre.shiki code .s-_DF, html code.shiki .s-_DF{--shiki-default:#032563;--shiki-dark:#032563;--shiki-light:#032563}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 .s-fAs, html code.shiki .s-fAs{--shiki-default:#024C1A;--shiki-dark:#024C1A;--shiki-light:#024C1A}",{"title":464,"searchDepth":481,"depth":481,"links":1261},[1262,1263,1264,1265,1266,1267,1275,1276,1277],{"id":185,"depth":481,"text":186},{"id":231,"depth":481,"text":232},{"id":291,"depth":481,"text":292},{"id":347,"depth":481,"text":348},{"id":415,"depth":481,"text":416},{"id":446,"depth":481,"text":447,"children":1268},[1269,1271,1273,1274],{"id":451,"depth":495,"text":1270},"Responsive \u003Cimg> with width descriptors and accurate sizes",{"id":601,"depth":495,"text":1272},"Format negotiation with \u003Cpicture> and a JPEG fallback",{"id":784,"depth":495,"text":785},{"id":960,"depth":495,"text":961},{"id":1062,"depth":481,"text":1063},{"id":1140,"depth":481,"text":1141},{"id":1220,"depth":481,"text":1221},"Production playbook for the image delivery pipeline: responsive sizing, next-gen formats, CDN transforms, priority hints, decode cost, and CLS-safe media.","md",{"slug":1281,"type":1282,"breadcrumb":1283,"datePublished":1288,"dateModified":1288},"image-media-optimization","pillar",[1284,1286],{"name":1285,"url":374},"Home",{"name":5,"url":1287},"\u002Fimage-media-optimization\u002F","2026-06-18",true,"\u002Fimage-media-optimization",{"title":1292,"description":1293},"Image & Media Optimization for Core Web Vitals","Engineer the image delivery pipeline for LCP under 2.5s and CLS under 0.1: responsive srcset, AVIF\u002FWebP, image CDNs, fetchpriority, and safe lazy-loading.","image-media-optimization\u002Findex","0GroWvXSOdPDqMdTRqWHjpc4Cotp9O-26DIKsAMkvB0",[1297,1301],{"title":1298,"path":1299,"stem":1300,"children":-1},"Best Lighthouse CI Setup for Frontend Pipelines","\u002Fcore-web-vitals-measurement\u002Funderstanding-core-web-vitals-thresholds\u002Fbest-lighthouse-ci-setup-for-frontend-pipelines","core-web-vitals-measurement\u002Funderstanding-core-web-vitals-thresholds\u002Fbest-lighthouse-ci-setup-for-frontend-pipelines\u002Findex",{"title":1302,"path":1303,"stem":1304,"children":-1},"Image CDNs and fetchpriority","\u002Fimage-media-optimization\u002Fimage-cdns-and-fetchpriority","image-media-optimization\u002Fimage-cdns-and-fetchpriority\u002Findex",1782237170597]