[{"data":1,"prerenderedAt":1228},["ShallowReactive",2],{"content:\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Ffinding-layout-shift-sources-in-devtools":3,"surroundings:\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Ffinding-layout-shift-sources-in-devtools":1219},{"id":4,"title":5,"body":6,"description":1199,"extension":1200,"meta":1201,"navigation":1212,"path":1213,"seo":1214,"stem":1217,"__hash__":1218},"content\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Ffinding-layout-shift-sources-in-devtools\u002Findex.md","Finding Layout Shift Sources in DevTools",{"type":7,"value":8,"toc":1185},"minimark",[9,14,39,49,205,210,249,253,283,289,295,312,318,450,454,459,462,728,731,735,746,900,903,907,910,914,921,1031,1035,1054,1058,1061,1067,1077,1083,1089,1109,1113,1125,1134,1143,1147,1170,1175,1178,1181],[10,11,13],"h1",{"id":12},"how-to-find-the-source-of-every-layout-shift-in-chrome-devtools","How to Find the Source of Every Layout Shift in Chrome DevTools",[15,16,17,18,23,24,28,29,33,34,38],"p",{},"This guide is the lab companion to ",[19,20,22],"a",{"href":21},"\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002F","Reducing Cumulative Layout Shift (CLS)",", part of ",[19,25,27],{"href":26},"\u002Fcore-web-vitals-measurement\u002F","Core Web Vitals & Measurement",". RUM tells you CLS is ",[30,31,32],"code",{},"0.17"," at p75 on a template; it rarely tells you which of the forty elements that moved was the ",[35,36,37],"em",{},"cause",". DevTools can, if you know where to look and how to distinguish the element that moved from the element that made it move.",[15,40,41,42,45,46,48],{},"That distinction is the crux. A layout shift entry lists the nodes whose position changed — the ",[35,43,44],{},"victims",". The ",[35,47,37],{}," is usually something that changed size or was inserted above them: an image that loaded without dimensions, a font that swapped, an ad that resized. Effective debugging means walking from the victims back to the cause, at the exact moment the shift occurred.",[15,50,51],{},[52,53,59,60,59,67,59,71,59,74,59,92,59,100,59,106,59,114,59,121,59,126,59,130,59,133,59,137,59,141,59,145,59,148,59,152,59,155,59,158,59,164,59,168,59,171,59,174,59,177,59,181,59,184,59,193,59,197,59,201,59],"svg",{"viewBox":54,"width":55,"role":56,"ariaLabel":57,"style":58},"0 0 760 150","100%","img","Workflow from a field CLS value to the specific element and change that caused the shift, using DevTools tools in sequence.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[61,62],"rect",{"className":63,"x":65,"y":65,"width":55,"height":55,"fill":66},[64],"svg-canvas","0","#ffffff",[68,69,70],"title",{},"From CLS number to root cause",[72,73,57],"desc",{},[75,76,77],"defs",{},[78,79,86],"marker",{"id":80,"viewBox":81,"refX":82,"refY":83,"markerWidth":84,"markerHeight":84,"orient":85},"fa69cb796d","0 0 10 10","9","5","7","auto-start-reverse",[87,88],"path",{"d":89,"fill":90,"style":91},"M0 0 L10 5 L0 10 z","currentColor","fill-opacity:0.7",[61,93],{"x":94,"y":94,"width":95,"height":96,"rx":97,"fill":98,"stroke":90,"style":99},"1","758","148","10","none","stroke-opacity:0.18",[101,102,70],"text",{"x":103,"y":104,"fill":90,"style":105},"28.0","34.0","font-size:16px;font-weight:700",[61,107],{"x":103,"y":108,"width":109,"height":110,"rx":111,"fill":112,"stroke":112,"style":113},"56.0","108.8","72.0","6","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[101,115,120],{"x":116,"y":117,"fill":90,"style":118,"textAnchor":119},"82.4","78.0","font-size:13px;font-weight:700","middle","Reproduce",[101,122,125],{"x":116,"y":123,"fill":90,"style":124,"textAnchor":119},"96.0","font-size:12px","same viewport +",[101,127,129],{"x":116,"y":128,"fill":90,"style":124,"textAnchor":119},"112.0","network",[61,131],{"x":132,"y":108,"width":109,"height":110,"rx":111,"fill":112,"stroke":112,"style":113},"176.8",[101,134,136],{"x":135,"y":117,"fill":90,"style":118,"textAnchor":119},"231.2","Layout Shifts",[101,138,140],{"x":135,"y":139,"fill":90,"style":118,"textAnchor":119},"95.0","track",[101,142,144],{"x":135,"y":143,"fill":90,"style":124,"textAnchor":119},"113.0","find the cluster",[61,146],{"x":147,"y":108,"width":109,"height":110,"rx":111,"fill":112,"stroke":112,"style":113},"325.6",[101,149,151],{"x":150,"y":117,"fill":90,"style":118,"textAnchor":119},"380.0","Shift sources",[101,153,154],{"x":150,"y":123,"fill":90,"style":124,"textAnchor":119},"which nodes",[101,156,157],{"x":150,"y":128,"fill":90,"style":124,"textAnchor":119},"moved",[61,159],{"x":160,"y":108,"width":109,"height":110,"rx":111,"fill":161,"stroke":162,"style":163},"474.4","#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[101,165,167],{"x":166,"y":117,"fill":90,"style":118,"textAnchor":119},"528.8","Walk upward",[101,169,170],{"x":166,"y":123,"fill":90,"style":124,"textAnchor":119},"what changed",[101,172,173],{"x":166,"y":128,"fill":90,"style":124,"textAnchor":119},"above",[61,175],{"x":176,"y":108,"width":109,"height":110,"rx":111,"fill":112,"stroke":112,"style":113},"623.2",[101,178,180],{"x":179,"y":117,"fill":90,"style":118,"textAnchor":119},"677.6","Confirm",[101,182,183],{"x":179,"y":123,"fill":90,"style":124,"textAnchor":119},"fix and re-record",[185,186],"line",{"x1":187,"y1":188,"x2":189,"y2":188,"stroke":90,"strokeWidth":190,"style":191,"markerEnd":192},"136.8","92.0","174.8","1.5","stroke-opacity:0.6","url(#fa69cb796d)",[185,194],{"x1":195,"y1":188,"x2":196,"y2":188,"stroke":90,"strokeWidth":190,"style":191,"markerEnd":192},"285.6","323.6",[185,198],{"x1":199,"y1":188,"x2":200,"y2":188,"stroke":90,"strokeWidth":190,"style":191,"markerEnd":192},"434.4","472.4",[185,202],{"x1":203,"y1":188,"x2":204,"y2":188,"stroke":90,"strokeWidth":190,"style":191,"markerEnd":192},"583.2","621.2",[206,207,209],"h2",{"id":208},"rapid-diagnosis","Rapid Diagnosis",[211,212,213,221,231,237,243],"ul",{},[214,215,216,220],"li",{},[217,218,219],"strong",{},"Match the field conditions."," Use the viewport and throttling from your RUM's failing segment. Many shifts only occur at specific widths or when a resource is slow.",[214,222,223,226,227,230],{},[217,224,225],{},"Enable the Layout Shift Regions overlay"," (Rendering drawer → \"Layout Shift Regions\") and reload. Moved areas flash blue; it is the fastest way to see ",[35,228,229],{},"where"," shifts happen.",[214,232,233,236],{},[217,234,235],{},"Record a Performance trace with \"Screenshots\" on."," The Layout Shifts track shows each shift as a diamond, grouped into clusters (session windows) with their scores.",[214,238,239,242],{},[217,240,241],{},"Click the largest cluster."," The summary lists each shift's score and the moved nodes; hovering a node highlights it on the page.",[214,244,245,248],{},[217,246,247],{},"Note the timestamp."," Look at the Network and Main tracks at that exact moment: what finished loading or executing just before?",[206,250,252],{"id":251},"root-cause-analysis-the-five-usual-culprits","Root Cause Analysis: The Five Usual Culprits",[15,254,255,258,259,262,263,266,267,270,271,274,275,278,279,282],{},[217,256,257],{},"1. Media without reserved dimensions."," An ",[30,260,261],{},"\u003Cimg>",", ",[30,264,265],{},"\u003Cvideo>"," or ",[30,268,269],{},"\u003Ciframe>"," with no ",[30,272,273],{},"width","\u002F",[30,276,277],{},"height"," attributes or CSS ",[30,280,281],{},"aspect-ratio"," renders at zero height, then expands when its dimensions are known. In the trace, the shift coincides with the resource's response arriving.",[15,284,285,288],{},[217,286,287],{},"2. Late-inserted content."," Banners, ads, embeds, \"related items\" rails or client-rendered components inserted above existing content. The shift coincides with a script task or a fetch completing.",[15,290,291,294],{},[217,292,293],{},"3. Web font swaps."," Text re-renders in the web font with different metrics, changing line heights and wrapping. The shift coincides with a font request completing, and the moved nodes are text blocks and everything below them.",[15,296,297,300,301,262,304,262,306,266,309,311],{},[217,298,299],{},"4. Layout property animations."," Animations or transitions on ",[30,302,303],{},"top",[30,305,277],{},[30,307,308],{},"margin",[30,310,273],{}," shift elements every frame. The trace shows a series of small shifts in quick succession.",[15,313,314,317],{},[217,315,316],{},"5. Hydration or client re-render."," A framework replaces server markup with differently sized client markup. The shift coincides with the hydration long task.",[15,319,320],{},[52,321,59,324,59,327,59,330,59,332,59,335,59,337,59,342,59,349,59,353,59,357,59,360,59,364,59,368,59,372,59,374,59,377,59,379,59,382,59,385,59,389,59,391,59,394,59,396,59,399,59,402,59,406,59,408,59,411,59,413,59,416,59,419,59,423,59,425,59,428,59,430,59,433,59,436,59,440,59,442,59,445,59,447,59],{"viewBox":322,"width":55,"role":56,"ariaLabel":323,"style":58},"0 0 760 258","For each common layout shift cause, what to look for in the trace at the moment of the shift.",[61,325],{"className":326,"x":65,"y":65,"width":55,"height":55,"fill":66},[64],[68,328,329],{},"Matching the shift timestamp to its cause",[72,331,323],{},[61,333],{"x":94,"y":94,"width":95,"height":334,"rx":97,"fill":98,"stroke":90,"style":99},"256",[101,336,329],{"x":103,"y":104,"fill":90,"style":105},[61,338],{"x":103,"y":108,"width":339,"height":340,"rx":65,"fill":90,"stroke":90,"style":341},"132.5","30.0","fill-opacity:0.06;stroke-opacity:0.4",[101,343,348],{"x":344,"y":345,"fill":90,"style":346,"textAnchor":347},"38.0","75.5","font-size:12.5px;font-weight:700","start","Cause",[61,350],{"x":351,"y":108,"width":352,"height":340,"rx":65,"fill":90,"stroke":90,"style":341},"160.5","285.7",[101,354,356],{"x":355,"y":345,"fill":90,"style":346,"textAnchor":119},"303.4","In the trace at shift time",[61,358],{"x":359,"y":108,"width":352,"height":340,"rx":65,"fill":90,"stroke":90,"style":341},"446.3",[101,361,363],{"x":362,"y":345,"fill":90,"style":346,"textAnchor":119},"589.1","Moved nodes",[61,365],{"x":103,"y":366,"width":339,"height":340,"rx":65,"fill":98,"stroke":90,"style":367},"86.0","stroke-opacity:0.35",[101,369,371],{"x":344,"y":370,"fill":90,"style":346,"textAnchor":347},"105.5","Unsized media",[61,373],{"x":351,"y":366,"width":352,"height":340,"rx":65,"fill":161,"stroke":162,"style":163},[101,375,376],{"x":355,"y":370,"fill":90,"style":124,"textAnchor":119},"image\u002Fiframe response just ended",[61,378],{"x":359,"y":366,"width":352,"height":340,"rx":65,"fill":98,"stroke":90,"style":367},[101,380,381],{"x":362,"y":370,"fill":90,"style":124,"textAnchor":119},"Everything below the media",[61,383],{"x":103,"y":384,"width":339,"height":340,"rx":65,"fill":98,"stroke":90,"style":367},"116.0",[101,386,388],{"x":344,"y":387,"fill":90,"style":346,"textAnchor":347},"135.5","Late insertion",[61,390],{"x":351,"y":384,"width":352,"height":340,"rx":65,"fill":161,"stroke":162,"style":163},[101,392,393],{"x":355,"y":387,"fill":90,"style":124,"textAnchor":119},"script task or fetch just ended",[61,395],{"x":359,"y":384,"width":352,"height":340,"rx":65,"fill":98,"stroke":90,"style":367},[101,397,398],{"x":362,"y":387,"fill":90,"style":124,"textAnchor":119},"Siblings after the insertion",[61,400],{"x":103,"y":401,"width":339,"height":340,"rx":65,"fill":98,"stroke":90,"style":367},"146.0",[101,403,405],{"x":344,"y":404,"fill":90,"style":346,"textAnchor":347},"165.5","Font swap",[61,407],{"x":351,"y":401,"width":352,"height":340,"rx":65,"fill":90,"stroke":90,"style":341},[101,409,410],{"x":355,"y":404,"fill":90,"style":124,"textAnchor":119},"font request just ended",[61,412],{"x":359,"y":401,"width":352,"height":340,"rx":65,"fill":98,"stroke":90,"style":367},[101,414,415],{"x":362,"y":404,"fill":90,"style":124,"textAnchor":119},"Text blocks and below",[61,417],{"x":103,"y":418,"width":339,"height":340,"rx":65,"fill":98,"stroke":90,"style":367},"176.0",[101,420,422],{"x":344,"y":421,"fill":90,"style":346,"textAnchor":347},"195.5","Layout animation",[61,424],{"x":351,"y":418,"width":352,"height":340,"rx":65,"fill":90,"stroke":90,"style":341},[101,426,427],{"x":355,"y":421,"fill":90,"style":124,"textAnchor":119},"many tiny shifts per second",[61,429],{"x":359,"y":418,"width":352,"height":340,"rx":65,"fill":98,"stroke":90,"style":367},[101,431,432],{"x":362,"y":421,"fill":90,"style":124,"textAnchor":119},"Animated element and siblings",[61,434],{"x":103,"y":435,"width":339,"height":340,"rx":65,"fill":98,"stroke":90,"style":367},"206.0",[101,437,439],{"x":344,"y":438,"fill":90,"style":346,"textAnchor":347},"225.5","Hydration re-render",[61,441],{"x":351,"y":435,"width":352,"height":340,"rx":65,"fill":161,"stroke":162,"style":163},[101,443,444],{"x":355,"y":438,"fill":90,"style":124,"textAnchor":119},"long hydration task",[61,446],{"x":359,"y":435,"width":352,"height":340,"rx":65,"fill":98,"stroke":90,"style":367},[101,448,449],{"x":362,"y":438,"fill":90,"style":124,"textAnchor":119},"Component and below",[206,451,453],{"id":452},"step-by-step-workflow","Step-by-Step Workflow",[455,456,458],"h3",{"id":457},"_1-log-shift-sources-with-their-rectangles","1. Log shift sources with their rectangles",[15,460,461],{},"The Performance panel shows moved nodes, but the console gives you precise before\u002Fafter rectangles you can reason about.",[463,464,469],"pre",{"className":465,"code":466,"language":467,"meta":468,"style":468},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","new PerformanceObserver((list) => {\n  for (const e of list.getEntries()) {\n    if (e.hadRecentInput) continue;\n    console.groupCollapsed(`shift ${e.value.toFixed(4)} at ${Math.round(e.startTime)}ms`);\n    for (const s of e.sources) {\n      console.log(s.node, 'from', s.previousRect.toJSON(), 'to', s.currentRect.toJSON());\n    }\n    console.groupEnd();\n  }\n}).observe({ type: 'layout-shift', buffered: true });\n\u002F\u002F trade-off: sources lists at most five nodes per shift, prioritised by\n\u002F\u002F impact. A shift that moves fifty nodes shows five — usually enough, but the\n\u002F\u002F true cause may not be among them; walk up the DOM from the first one.\n","javascript","",[30,470,471,500,528,543,609,627,662,668,679,685,709,716,722],{"__ignoreMap":468},[472,473,475,479,483,487,491,494,497],"span",{"class":185,"line":474},1,[472,476,478],{"class":477},"sPARh","new",[472,480,482],{"class":481},"smZ65"," PerformanceObserver",[472,484,486],{"class":485},"saISM","((",[472,488,490],{"class":489},"sQw3B","list",[472,492,493],{"class":485},") ",[472,495,496],{"class":477},"=>",[472,498,499],{"class":485}," {\n",[472,501,503,506,509,512,516,519,522,525],{"class":185,"line":502},2,[472,504,505],{"class":477},"  for",[472,507,508],{"class":485}," (",[472,510,511],{"class":477},"const",[472,513,515],{"class":514},"sPXB4"," e",[472,517,518],{"class":477}," of",[472,520,521],{"class":485}," list.",[472,523,524],{"class":481},"getEntries",[472,526,527],{"class":485},"()) {\n",[472,529,531,534,537,540],{"class":185,"line":530},3,[472,532,533],{"class":477},"    if",[472,535,536],{"class":485}," (e.hadRecentInput) ",[472,538,539],{"class":477},"continue",[472,541,542],{"class":485},";\n",[472,544,546,549,552,555,559,562,565,568,570,573,575,578,581,584,587,589,592,594,596,598,601,603,606],{"class":185,"line":545},4,[472,547,548],{"class":485},"    console.",[472,550,551],{"class":481},"groupCollapsed",[472,553,554],{"class":485},"(",[472,556,558],{"class":557},"sZ8jY","`shift ${",[472,560,561],{"class":485},"e",[472,563,564],{"class":557},".",[472,566,567],{"class":485},"value",[472,569,564],{"class":557},[472,571,572],{"class":481},"toFixed",[472,574,554],{"class":557},[472,576,577],{"class":514},"4",[472,579,580],{"class":557},")",[472,582,583],{"class":557},"} at ${",[472,585,586],{"class":485},"Math",[472,588,564],{"class":557},[472,590,591],{"class":481},"round",[472,593,554],{"class":557},[472,595,561],{"class":485},[472,597,564],{"class":557},[472,599,600],{"class":485},"startTime",[472,602,580],{"class":557},[472,604,605],{"class":557},"}ms`",[472,607,608],{"class":485},");\n",[472,610,612,615,617,619,622,624],{"class":185,"line":611},5,[472,613,614],{"class":477},"    for",[472,616,508],{"class":485},[472,618,511],{"class":477},[472,620,621],{"class":514}," s",[472,623,518],{"class":477},[472,625,626],{"class":485}," e.sources) {\n",[472,628,630,633,636,639,642,645,648,651,654,657,659],{"class":185,"line":629},6,[472,631,632],{"class":485},"      console.",[472,634,635],{"class":481},"log",[472,637,638],{"class":485},"(s.node, ",[472,640,641],{"class":557},"'from'",[472,643,644],{"class":485},", s.previousRect.",[472,646,647],{"class":481},"toJSON",[472,649,650],{"class":485},"(), ",[472,652,653],{"class":557},"'to'",[472,655,656],{"class":485},", s.currentRect.",[472,658,647],{"class":481},[472,660,661],{"class":485},"());\n",[472,663,665],{"class":185,"line":664},7,[472,666,667],{"class":485},"    }\n",[472,669,671,673,676],{"class":185,"line":670},8,[472,672,548],{"class":485},[472,674,675],{"class":481},"groupEnd",[472,677,678],{"class":485},"();\n",[472,680,682],{"class":185,"line":681},9,[472,683,684],{"class":485},"  }\n",[472,686,688,691,694,697,700,703,706],{"class":185,"line":687},10,[472,689,690],{"class":485},"}).",[472,692,693],{"class":481},"observe",[472,695,696],{"class":485},"({ type: ",[472,698,699],{"class":557},"'layout-shift'",[472,701,702],{"class":485},", buffered: ",[472,704,705],{"class":514},"true",[472,707,708],{"class":485}," });\n",[472,710,712],{"class":185,"line":711},11,[472,713,715],{"class":714},"sjfSM","\u002F\u002F trade-off: sources lists at most five nodes per shift, prioritised by\n",[472,717,719],{"class":185,"line":718},12,[472,720,721],{"class":714},"\u002F\u002F impact. A shift that moves fifty nodes shows five — usually enough, but the\n",[472,723,725],{"class":185,"line":724},13,[472,726,727],{"class":714},"\u002F\u002F true cause may not be among them; walk up the DOM from the first one.\n",[15,729,730],{},"Expected outcome: a list of shifts with nodes and exact pixel deltas, which tells you the size of whatever was inserted or resized.",[455,732,734],{"id":733},"_2-find-what-changed-above-the-first-moved-node","2. Find what changed above the first moved node",[15,736,737,738,741,742,745],{},"The delta in ",[30,739,740],{},"previousRect.y"," → ",[30,743,744],{},"currentRect.y"," is the height of the change. Walk the DOM upwards and to the preceding siblings of the first moved node looking for an element of that height that appeared or grew. The Elements panel's DOM breakpoints (\"Break on → subtree modifications\") on the parent pause execution at the insertion, showing the call stack responsible.",[463,747,749],{"className":465,"code":748,"language":467,"meta":468,"style":468},"\u002F\u002F Pause when anything is inserted into the main content area.\nconst target = document.querySelector('main');\nnew MutationObserver((records) => {\n  for (const r of records) for (const n of r.addedNodes) {\n    if (n.nodeType === 1 && n.getBoundingClientRect().height > 0) { debugger; }\n  }\n}).observe(target, { childList: true, subtree: true });\n\u002F\u002F trade-off: this pauses on every visible insertion, including legitimate\n\u002F\u002F below-the-fold ones. Narrow the selector once you know roughly where the shift is.\n",[30,750,751,756,779,797,828,868,872,890,895],{"__ignoreMap":468},[472,752,753],{"class":185,"line":474},[472,754,755],{"class":714},"\u002F\u002F Pause when anything is inserted into the main content area.\n",[472,757,758,760,763,766,769,772,774,777],{"class":185,"line":502},[472,759,511],{"class":477},[472,761,762],{"class":514}," target",[472,764,765],{"class":477}," =",[472,767,768],{"class":485}," document.",[472,770,771],{"class":481},"querySelector",[472,773,554],{"class":485},[472,775,776],{"class":557},"'main'",[472,778,608],{"class":485},[472,780,781,783,786,788,791,793,795],{"class":185,"line":530},[472,782,478],{"class":477},[472,784,785],{"class":481}," MutationObserver",[472,787,486],{"class":485},[472,789,790],{"class":489},"records",[472,792,493],{"class":485},[472,794,496],{"class":477},[472,796,499],{"class":485},[472,798,799,801,803,805,808,810,813,816,818,820,823,825],{"class":185,"line":545},[472,800,505],{"class":477},[472,802,508],{"class":485},[472,804,511],{"class":477},[472,806,807],{"class":514}," r",[472,809,518],{"class":477},[472,811,812],{"class":485}," records) ",[472,814,815],{"class":477},"for",[472,817,508],{"class":485},[472,819,511],{"class":477},[472,821,822],{"class":514}," n",[472,824,518],{"class":477},[472,826,827],{"class":485}," r.addedNodes) {\n",[472,829,830,832,835,838,841,844,847,850,853,856,859,862,865],{"class":185,"line":611},[472,831,533],{"class":477},[472,833,834],{"class":485}," (n.nodeType ",[472,836,837],{"class":477},"===",[472,839,840],{"class":514}," 1",[472,842,843],{"class":477}," &&",[472,845,846],{"class":485}," n.",[472,848,849],{"class":481},"getBoundingClientRect",[472,851,852],{"class":485},"().height ",[472,854,855],{"class":477},">",[472,857,858],{"class":514}," 0",[472,860,861],{"class":485},") { ",[472,863,864],{"class":477},"debugger",[472,866,867],{"class":485},"; }\n",[472,869,870],{"class":185,"line":629},[472,871,684],{"class":485},[472,873,874,876,878,881,883,886,888],{"class":185,"line":664},[472,875,690],{"class":485},[472,877,693],{"class":481},[472,879,880],{"class":485},"(target, { childList: ",[472,882,705],{"class":514},[472,884,885],{"class":485},", subtree: ",[472,887,705],{"class":514},[472,889,708],{"class":485},[472,891,892],{"class":185,"line":670},[472,893,894],{"class":714},"\u002F\u002F trade-off: this pauses on every visible insertion, including legitimate\n",[472,896,897],{"class":185,"line":681},[472,898,899],{"class":714},"\u002F\u002F below-the-fold ones. Narrow the selector once you know roughly where the shift is.\n",[15,901,902],{},"Expected outcome: the exact script and line that inserted the content.",[455,904,906],{"id":905},"_3-correlate-with-network-and-main-thread-activity","3. Correlate with network and main-thread activity",[15,908,909],{},"In the trace, zoom to the shift and read the tracks above it. A font or image request ending at that instant, or a task from a third-party script, is almost always the trigger. Hover the request to see its initiator.",[455,911,913],{"id":912},"_4-confirm-with-a-targeted-change","4. Confirm with a targeted change",[15,915,916,917,920],{},"Apply a minimal fix — add dimensions, reserve space, set ",[30,918,919],{},"font-display: optional"," temporarily — and re-record. If the shift disappears, you have the cause. If a smaller shift remains, repeat; pages often have two or three independent sources.",[15,922,923],{},[52,924,59,927,59,930,59,933,59,935,59,938,59,940,59,944,59,950,59,956,59,959,59,964,59,969,59,973,59,978,59,983,59,986,59,990,59,996,59,1002,59,1006,59,1010,59,1014,59,1018,59,1022,59,1026,59],{"viewBox":925,"width":55,"role":56,"ariaLabel":926,"style":58},"0 0 760 242","Trace excerpt showing a font response and an ad script ending just before two layout shifts, identifying each shift's trigger.",[61,928],{"className":929,"x":65,"y":65,"width":55,"height":55,"fill":66},[64],[68,931,932],{},"Correlating a shift with the resource that caused it",[72,934,926],{},[61,936],{"x":94,"y":94,"width":95,"height":937,"rx":97,"fill":98,"stroke":90,"style":99},"240",[101,939,932],{"x":103,"y":104,"fill":90,"style":105},[101,941,943],{"x":103,"y":942,"fill":90,"style":346},"74.0","Font",[61,945],{"x":946,"y":108,"width":947,"height":948,"rx":949,"fill":90,"stroke":90,"style":341},"143.4","247.0","26.0","3",[101,951,955],{"x":952,"y":953,"fill":90,"style":954,"textAnchor":119},"266.9","73.5","font-size:11.5px","web font request",[101,957,958],{"x":103,"y":128,"fill":90,"style":346},"Ad",[61,960],{"x":961,"y":962,"width":963,"height":948,"rx":949,"fill":90,"stroke":90,"style":341},"273.1","94.0","301.0",[101,965,968],{"x":966,"y":967,"fill":90,"style":954,"textAnchor":119},"423.5","111.5","ad script + creative",[101,970,972],{"x":103,"y":971,"fill":90,"style":346},"150.0","Shifts",[61,974],{"x":975,"y":976,"width":977,"height":948,"rx":949,"fill":161,"stroke":162,"style":163},"391.9","132.0","30.9",[101,979,982],{"x":980,"y":981,"fill":90,"style":954,"textAnchor":119},"407.3","149.5","0.04",[61,984],{"x":985,"y":976,"width":977,"height":948,"rx":949,"fill":161,"stroke":162,"style":163},"575.5",[101,987,989],{"x":988,"y":981,"fill":90,"style":954,"textAnchor":119},"591.0","0.11",[185,991],{"x1":992,"y1":993,"x2":994,"y2":993,"stroke":90,"style":995},"77.9","172.0","726.0","stroke-opacity:0.4",[101,997,1001],{"x":998,"y":999,"fill":1000,"style":954,"textAnchor":119},"88.6","189.0","#51617a","0ms",[101,1003,1005],{"x":1004,"y":999,"fill":1000,"style":954,"textAnchor":119},"185.9","500ms",[101,1007,1009],{"x":1008,"y":999,"fill":1000,"style":954,"textAnchor":119},"293.9","1000ms",[101,1011,1013],{"x":1012,"y":999,"fill":1000,"style":954,"textAnchor":119},"401.9","1500ms",[101,1015,1017],{"x":1016,"y":999,"fill":1000,"style":954,"textAnchor":119},"510.0","2000ms",[101,1019,1021],{"x":1020,"y":999,"fill":1000,"style":954,"textAnchor":119},"618.0","2500ms",[101,1023,1025],{"x":1024,"y":999,"fill":1000,"style":954,"textAnchor":119},"712.3","3000ms",[101,1027,1030],{"x":103,"y":1028,"fill":1000,"style":1029},"220.0","font-size:12.5px","Each shift starts the instant a request completes — the font swap at 1.45s and the ad insertion at 2.3s.",[206,1032,1034],{"id":1033},"verification","Verification",[15,1036,1037,1038,1041,1042,1045,1046,1049,1050,1053],{},"After fixing, run the page with the Layout Shift Regions overlay on at each relevant width and confirm no blue flashes outside of user-initiated changes. Record a final trace and check that the Layout Shifts track has no clusters above ",[30,1039,1040],{},"0.01",". Then confirm in RUM with the ",[30,1043,1044],{},"web-vitals"," attribution build: ",[30,1047,1048],{},"attribution.largestShiftTarget"," for the template should change from the old culprit to nothing in particular, and p75 CLS should drop below ",[30,1051,1052],{},"0.1"," over the following days.",[206,1055,1057],{"id":1056},"shifts-the-lab-tends-to-miss","Shifts the Lab Tends to Miss",[15,1059,1060],{},"Some shifts depend on conditions a single lab run does not reproduce. Know them so you can force them deliberately.",[15,1062,1063,1066],{},[217,1064,1065],{},"Slow third-party responses."," An ad or embed that loads in 300ms in your lab may take 3s in the field, landing after the content below it has rendered. Use request blocking with a delay (or a proxy) to slow specific third-party origins.",[15,1068,1069,1072,1073,1076],{},[217,1070,1071],{},"Cached vs uncached fonts."," On repeat visits fonts are cached and render immediately without a swap. Test with the cache disabled ",[35,1074,1075],{},"and"," enabled; the first visit is usually the problem.",[15,1078,1079,1082],{},[217,1080,1081],{},"User-specific content."," Logged-in banners, personalised recommendations and A\u002FB test variants insert different content for different users. Test the variants your RUM shows are most common among high-CLS sessions.",[15,1084,1085,1088],{},[217,1086,1087],{},"Scroll-dependent shifts."," Lazy-loaded images without dimensions only shift when scrolled into view. Scripted traces that do not scroll miss them entirely; add a slow scripted scroll to the recording.",[15,1090,1091,1094,1095,1098,1099,274,1102,274,1105,1108],{},[217,1092,1093],{},"Viewport resizes on mobile."," The mobile browser's address bar collapsing changes the viewport height, which can resize ",[30,1096,1097],{},"vh","-based elements. Use ",[30,1100,1101],{},"svh",[30,1103,1104],{},"lvh",[30,1106,1107],{},"dvh"," units deliberately and test on a real device.",[206,1110,1112],{"id":1111},"faq","FAQ",[1114,1115,1118,1122],"details",{"className":1116},[1117],"faq-item",[1119,1120,1121],"summary",{},"Why does the moved element not look like it moved?",[15,1123,1124],{},"Shift sources report elements whose layout position changed between frames, even by a few pixels, and even if they are below the fold or partly off-screen. A footer that moved 4px counts if it was in the viewport. The score weights by how much of the viewport moved and how far, so small movements of large elements still add up.",[1114,1126,1128,1131],{"className":1127},[1117],[1119,1129,1130],{},"Does a shift inside a scroll container count?",[15,1132,1133],{},"Yes, if the shifted elements are visible within the viewport. Shifts are computed relative to the viewport, so content moving inside a visible scrollable panel contributes just like content in the main document.",[1114,1135,1137,1140],{"className":1136},[1117],[1119,1138,1139],{},"Can I see layout shifts in Lighthouse instead of a trace?",[15,1141,1142],{},"Lighthouse's \"Avoid large layout shifts\" audit lists the elements that contributed most to CLS during its load, with scores, which is a quick first pass. It only covers the load it observed — one viewport, one network profile, no scrolling and no interaction — so it misses most of the shifts described in the section on what the lab tends to miss. Use it to triage, then reproduce in the Performance panel with the conditions your field data points at.",[206,1144,1146],{"id":1145},"related","Related",[211,1148,1149,1156,1163],{},[214,1150,1151,1155],{},[19,1152,1154],{"href":1153},"\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Fdebugging-cls-caused-by-dynamic-ad-injection\u002F","Debugging CLS caused by dynamic ad injection"," — applying this workflow to ad slots.",[214,1157,1158,1162],{},[19,1159,1161],{"href":1160},"\u002Fcore-web-vitals-measurement\u002Ffont-loading-and-text-rendering-performance\u002Ffixing-cls-from-web-font-swap\u002F","Fixing CLS from web font swap"," — the fix for the font-swap pattern.",[214,1164,1165,1169],{},[19,1166,1168],{"href":1167},"\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Ffixing-cls-from-skeleton-screens-that-resize\u002F","Fixing CLS from skeleton screens that resize"," — when the cause is a placeholder.",[1171,1172,1174],"script",{"type":1173},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Find the Source of Every Layout Shift in Chrome DevTools\",\n  \"description\": \"A practical DevTools workflow for turning a CLS number into the specific element, cause and moment that produced each shift.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Log shift sources with their rectangles\",\n      \"text\": \"The Performance panel shows moved nodes, but the console gives you precise before\u002Fafter rectangles you can reason about.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Find what changed above the first moved node\",\n      \"text\": \"The delta in previousRect.y → currentRect.y is the height of the change.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Correlate with network and main-thread activity\",\n      \"text\": \"In the trace, zoom to the shift and read the tracks above it.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Confirm with a targeted change\",\n      \"text\": \"Apply a minimal fix — add dimensions, reserve space, set font-display: optional temporarily — and re-record.\"\n    }\n  ]\n}\n",[1171,1176,1177],{"type":1173},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Find the Source of Every Layout Shift in Chrome DevTools\",\n  \"description\": \"A practical DevTools workflow for turning a CLS number into the specific element, cause and moment that produced each shift.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Ffinding-layout-shift-sources-in-devtools\u002F\"\n  }\n}\n",[1171,1179,1180],{"type":1173},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"Core Web Vitals & Measurement\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Reducing Cumulative Layout Shift (CLS)\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Finding Layout Shift Sources in DevTools\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Ffinding-layout-shift-sources-in-devtools\u002F\"\n    }\n  ]\n}\n",[1182,1183,1184],"style",{},"html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}",{"title":468,"searchDepth":502,"depth":502,"links":1186},[1187,1188,1189,1195,1196,1197,1198],{"id":208,"depth":502,"text":209},{"id":251,"depth":502,"text":252},{"id":452,"depth":502,"text":453,"children":1190},[1191,1192,1193,1194],{"id":457,"depth":530,"text":458},{"id":733,"depth":530,"text":734},{"id":905,"depth":530,"text":906},{"id":912,"depth":530,"text":913},{"id":1033,"depth":502,"text":1034},{"id":1056,"depth":502,"text":1057},{"id":1111,"depth":502,"text":1112},{"id":1145,"depth":502,"text":1146},"A practical DevTools workflow for turning a CLS number into the specific element, cause and moment that produced each shift.","md",{"slug":1202,"type":1203,"breadcrumb":1204,"datePublished":1211,"dateModified":1211},"finding-layout-shift-sources-in-devtools","article",[1205,1207,1208,1209],{"name":1206,"url":274},"Home",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1210},"\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Ffinding-layout-shift-sources-in-devtools\u002F","2026-10-06",true,"\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Ffinding-layout-shift-sources-in-devtools",{"title":1215,"description":1216},"Finding Layout Shift Sources in Chrome DevTools","Locate exactly which element moved, why, and when using the Layout Shifts track, shift regions overlay and the layout-shift sources API in Chrome DevTools.","core-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Ffinding-layout-shift-sources-in-devtools\u002Findex","UWul6ws-7fXxdWzdv-k4o8LMY2Kpoi0TH2Bt3qDzw7Y",[1220,1224],{"title":1221,"path":1222,"stem":1223,"children":-1},"Debugging CLS Caused by Dynamic Ad Injection","\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Fdebugging-cls-caused-by-dynamic-ad-injection","core-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Fdebugging-cls-caused-by-dynamic-ad-injection\u002Findex",{"title":1225,"path":1226,"stem":1227,"children":-1},"Fixing CLS from Animating Layout Properties","\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Ffixing-cls-from-animating-layout-properties","core-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Ffixing-cls-from-animating-layout-properties\u002Findex",1791308073819]