[{"data":1,"prerenderedAt":1440},["ShallowReactive",2],{"page-\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fprofiling-animations-in-devtools":3,"content-all-pages":1177},{"id":4,"title":5,"body":6,"description":1159,"extension":1160,"meta":1161,"navigation":320,"path":1173,"seo":1174,"stem":1175,"__hash__":1176},"content\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fprofiling-animations-in-devtools\u002Findex.md","Profiling CSS Animations in DevTools: Finding the Frame That Costs Too Much",{"type":7,"value":8,"toc":1148},"minimark",[9,13,32,35,38,43,66,73,75,79,82,221,223,227,234,238,376,789,791,795,814,824,854,879,907,927,941,943,947,964,993,995,999,1023,1025,1029,1061,1063,1067,1081,1092,1098,1104,1106,1110,1144],[10,11,5],"h1",{"id":12},"profiling-css-animations-in-devtools-finding-the-frame-that-costs-too-much",[14,15,16,17,21,22,25,26,31],"p",{},"\"It feels janky\" is not a bug report you can act on. Before you reach for ",[18,19,20],"code",{},"will-change",", add a ",[18,23,24],{},"translateZ(0)"," hack, or rewrite a keyframe set, you need to know which of the four rendering stages the browser is actually spending time in, and whether the animation is running on the compositor thread at all. This page, part of the ",[27,28,30],"a",{"href":29},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002F","Performance and GPU Acceleration"," section, is a click-by-click workflow for answering that in Chrome DevTools, with the Firefox and Safari equivalents at the end.",[14,33,34],{},"The narrow scenario: an animation that looks smooth on your machine and drops frames on a mid-range phone, and you need evidence about which stage is responsible before changing a line of CSS.",[36,37],"hr",{},[39,40,42],"h2",{"id":41},"why-measure-before-you-optimise","Why measure before you optimise",[14,44,45,46,48,49,53,54,57,58,61,62,65],{},"Every commonly repeated animation optimisation is conditional. ",[18,47,20],{}," helps when an element genuinely needs its own compositor layer and hurts when it creates dozens of them, because each layer costs GPU memory and every extra layer costs compositing time. Promoting an element can ",[50,51,52],"em",{},"increase"," paint cost by forcing text to re-rasterise. Swapping ",[18,55,56],{},"top"," for ",[18,59,60],{},"transform"," is nearly always right — but only after you have confirmed that layout is what is expensive, because if the frame is dominated by a heavy ",[18,63,64],{},"box-shadow"," repaint, the swap changes nothing.",[14,67,68,69,72],{},"Profiling also settles the one question static analysis cannot answer: whether an animation the browser ",[50,70,71],{},"could"," run on the compositor is actually doing so. Compositor eligibility is a runtime decision, and an animation can silently fall back to the main thread because an ancestor has a filter, because the element's layer was invalidated by a sibling, or simply because another property in the same rule forces layout. The tooling below distinguishes these cases in about a minute each, which is faster than reasoning about them.",[36,74],{},[39,76,78],{"id":77},"the-four-stages-and-where-each-property-enters","The four stages, and where each property enters",[14,80,81],{},"A frame runs the same pipeline every time. Which stage your animated property enters at is what determines its per-frame cost.",[83,84,90,91,90,95,90,99,90,106,90,118,90,124,90,129,90,137,90,140,90,144,90,147,90,151,90,154,90,158,90,161,90,165,90,170,90,174,90,177,90,182,90,187,90,191,90,193,90,196,90,199,90,204],"svg",{"viewBox":85,"role":86,"ariaLabel":87,"xmlns":88,"style":89},"0 0 720 330","img","The four rendering stages of a frame and which animated properties enter at each one","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0","\n  ",[92,93,94],"title",{},"Rendering pipeline stages in a frame",[96,97,98],"desc",{},"Recalculate Style, Layout, Paint and Composite shown in sequence, with layout properties entering at the start and transform and opacity entering only at composite.",[100,101,105],"text",{"x":102,"y":103,"style":104},"360","30","text-anchor:middle;fill:currentColor;font:700 18px sans-serif","Reading one frame in the Performance panel",[107,108],"rect",{"x":109,"y":110,"width":111,"height":112,"rx":113,"fill":114,"stroke":115,"strokeWidth":116,"opacity":117},"24","88","156","66","8","none","currentColor","1.5","0.55",[100,119,123],{"x":120,"y":121,"style":122},"102","116","text-anchor:middle;fill:currentColor;font:600 13px sans-serif","Recalc Style",[100,125,128],{"x":120,"y":126,"style":127},"136","text-anchor:middle;fill:currentColor;font:11px sans-serif;opacity:0.75","match selectors",[130,131],"line",{"x1":132,"y1":133,"x2":134,"y2":133,"stroke":115,"strokeWidth":135,"markerEnd":136},"182","121","192","2","url(#pr-arr)",[107,138],{"x":139,"y":110,"width":111,"height":112,"rx":113,"fill":114,"stroke":115,"strokeWidth":116,"opacity":117},"196",[100,141,143],{"x":142,"y":121,"style":122},"274","Layout",[100,145,146],{"x":142,"y":126,"style":127},"geometry",[130,148],{"x1":149,"y1":133,"x2":150,"y2":133,"stroke":115,"strokeWidth":135,"markerEnd":136},"354","364",[107,152],{"x":153,"y":110,"width":111,"height":112,"rx":113,"fill":114,"stroke":115,"strokeWidth":116,"opacity":117},"368",[100,155,157],{"x":156,"y":121,"style":122},"446","Paint",[100,159,160],{"x":156,"y":126,"style":127},"rasterise pixels",[130,162],{"x1":163,"y1":133,"x2":164,"y2":133,"stroke":115,"strokeWidth":135,"markerEnd":136},"526","536",[107,166],{"x":167,"y":110,"width":111,"height":112,"rx":113,"fill":168,"opacity":169},"540","#7aa2ff","0.2",[100,171,173],{"x":172,"y":121,"style":122},"618","Composite",[100,175,176],{"x":172,"y":126,"style":127},"assemble layers",[107,178],{"x":109,"y":134,"width":179,"height":180,"rx":113,"fill":114,"stroke":115,"strokeWidth":116,"opacity":181},"500","52","0.45",[100,183,186],{"x":142,"y":184,"style":185},"216","text-anchor:middle;fill:currentColor;font:12px sans-serif","width, height, top, margin, padding",[100,188,190],{"x":142,"y":189,"style":127},"234","enter here: all four stages run",[107,192],{"x":167,"y":134,"width":111,"height":180,"rx":113,"fill":168,"opacity":169},[100,194,195],{"x":172,"y":184,"style":185},"transform, opacity",[100,197,198],{"x":172,"y":189,"style":127},"composite only",[100,200,203],{"x":102,"y":201,"style":202},"292","text-anchor:middle;fill:currentColor;font:12px sans-serif;opacity:0.8","A dropped frame usually shows a long Layout or Paint band on the main thread.",[205,206,207,208,90],"defs",{},"\n    ",[209,210,216,217,207],"marker",{"id":211,"markerWidth":212,"markerHeight":212,"refX":213,"refY":214,"orient":215},"pr-arr","9","7","4","auto","\n      ",[218,219],"path",{"d":220,"fill":115},"M0 0 L8 4 L0 8 z",[36,222],{},[39,224,226],{"id":225},"a-reproducible-test-case","A reproducible test case",[14,228,229,230,233],{},"Before profiling a real page, it helps to profile something whose answer you already know, so you learn what each panel looks like when it is telling you good news versus bad news. The two bars below animate to the same visual result by different means: the top one scales a transform, the bottom one animates ",[18,231,232],{},"width",". Record both at once and the difference is unmistakable.",[235,236],"live-demo",{"name":237},"tk-compositor-vs-layout",[239,240,245],"pre",{"className":241,"code":242,"language":243,"meta":244,"style":244},"language-html shiki shiki-themes github-light-high-contrast github-dark-high-contrast","\u003Cp class=\"lane__title\">transform: scaleX() — composite only\u003C\u002Fp>\n\u003Cdiv class=\"lane\">\u003Cdiv class=\"bar bar--transform\">\u003C\u002Fdiv>\u003C\u002Fdiv>\n\n\u003Cp class=\"lane__title\">width — recalculates layout every frame\u003C\u002Fp>\n\u003Cdiv class=\"lane\">\u003Cdiv class=\"bar bar--width\">\u003C\u002Fdiv>\u003C\u002Fdiv>\n","html","",[18,246,247,277,315,322,342],{"__ignoreMap":244},[248,249,251,255,258,262,265,269,272,274],"span",{"class":130,"line":250},1,[248,252,254],{"class":253},"suds8","\u003C",[248,256,14],{"class":257},"sne4z",[248,259,261],{"class":260},"s-5SL"," class",[248,263,264],{"class":253},"=",[248,266,268],{"class":267},"sT6z2","\"lane__title\"",[248,270,271],{"class":253},">transform: scaleX() — composite only\u003C\u002F",[248,273,14],{"class":257},[248,275,276],{"class":253},">\n",[248,278,280,282,285,287,289,292,295,297,299,301,304,307,309,311,313],{"class":130,"line":279},2,[248,281,254],{"class":253},[248,283,284],{"class":257},"div",[248,286,261],{"class":260},[248,288,264],{"class":253},[248,290,291],{"class":267},"\"lane\"",[248,293,294],{"class":253},">\u003C",[248,296,284],{"class":257},[248,298,261],{"class":260},[248,300,264],{"class":253},[248,302,303],{"class":267},"\"bar bar--transform\"",[248,305,306],{"class":253},">\u003C\u002F",[248,308,284],{"class":257},[248,310,306],{"class":253},[248,312,284],{"class":257},[248,314,276],{"class":253},[248,316,318],{"class":130,"line":317},3,[248,319,321],{"emptyLinePlaceholder":320},true,"\n",[248,323,325,327,329,331,333,335,338,340],{"class":130,"line":324},4,[248,326,254],{"class":253},[248,328,14],{"class":257},[248,330,261],{"class":260},[248,332,264],{"class":253},[248,334,268],{"class":267},[248,336,337],{"class":253},">width — recalculates layout every frame\u003C\u002F",[248,339,14],{"class":257},[248,341,276],{"class":253},[248,343,345,347,349,351,353,355,357,359,361,363,366,368,370,372,374],{"class":130,"line":344},5,[248,346,254],{"class":253},[248,348,284],{"class":257},[248,350,261],{"class":260},[248,352,264],{"class":253},[248,354,291],{"class":267},[248,356,294],{"class":253},[248,358,284],{"class":257},[248,360,261],{"class":260},[248,362,264],{"class":253},[248,364,365],{"class":267},"\"bar bar--width\"",[248,367,306],{"class":253},[248,369,284],{"class":257},[248,371,306],{"class":253},[248,373,284],{"class":257},[248,375,276],{"class":253},[239,377,381],{"className":378,"code":379,"language":380,"meta":244,"style":244},"language-css shiki shiki-themes github-light-high-contrast github-dark-high-contrast",".lane__title { margin: 0 0 .35rem; font: 600 .85rem ui-monospace, monospace; }\n.lane {\n  height: 34px;\n  margin-bottom: 1.25rem;\n  border: 1px solid currentColor;\n  border-radius: 6px;\n  overflow: hidden;\n}\n.bar { height: 100%; background: #7aa2ff; }\n\n\u002F* Cheap: transform is handled on the compositor thread, no layout, no paint. *\u002F\n.bar--transform {\n  width: 100%;\n  transform-origin: left center;\n  animation: bar-scale 2s ease-in-out infinite alternate;\n}\n@keyframes bar-scale {\n  from { transform: scaleX(.15); }\n  to   { transform: scaleX(1); }\n}\n\n\u002F* Expensive: width is a layout property, so every frame runs Layout and Paint. *\u002F\n.bar--width { animation: bar-width 2s ease-in-out infinite alternate; }\n@keyframes bar-width {\n  from { width: 15%; }\n  to   { width: 100%; }\n}\n","css",[18,382,383,438,446,462,476,496,511,524,530,560,565,572,580,594,610,635,640,652,676,697,702,707,713,739,749,767,784],{"__ignoreMap":244},[248,384,385,388,391,394,397,400,403,406,410,413,416,418,421,424,426,429,432,435],{"class":130,"line":250},[248,386,387],{"class":260},".lane__title",[248,389,390],{"class":253}," { ",[248,392,393],{"class":260},"margin",[248,395,396],{"class":253},": ",[248,398,399],{"class":260},"0",[248,401,402],{"class":260}," 0",[248,404,405],{"class":260}," .35",[248,407,409],{"class":408},"sHUrx","rem",[248,411,412],{"class":253},"; ",[248,414,415],{"class":260},"font",[248,417,396],{"class":253},[248,419,420],{"class":260},"600",[248,422,423],{"class":260}," .85",[248,425,409],{"class":408},[248,427,428],{"class":260}," ui-monospace",[248,430,431],{"class":253},", ",[248,433,434],{"class":260},"monospace",[248,436,437],{"class":253},"; }\n",[248,439,440,443],{"class":130,"line":279},[248,441,442],{"class":260},".lane",[248,444,445],{"class":253}," {\n",[248,447,448,451,453,456,459],{"class":130,"line":317},[248,449,450],{"class":260},"  height",[248,452,396],{"class":253},[248,454,455],{"class":260},"34",[248,457,458],{"class":408},"px",[248,460,461],{"class":253},";\n",[248,463,464,467,469,472,474],{"class":130,"line":324},[248,465,466],{"class":260},"  margin-bottom",[248,468,396],{"class":253},[248,470,471],{"class":260},"1.25",[248,473,409],{"class":408},[248,475,461],{"class":253},[248,477,478,481,483,486,488,491,494],{"class":130,"line":344},[248,479,480],{"class":260},"  border",[248,482,396],{"class":253},[248,484,485],{"class":260},"1",[248,487,458],{"class":408},[248,489,490],{"class":260}," solid",[248,492,493],{"class":260}," currentColor",[248,495,461],{"class":253},[248,497,499,502,504,507,509],{"class":130,"line":498},6,[248,500,501],{"class":260},"  border-radius",[248,503,396],{"class":253},[248,505,506],{"class":260},"6",[248,508,458],{"class":408},[248,510,461],{"class":253},[248,512,514,517,519,522],{"class":130,"line":513},7,[248,515,516],{"class":260},"  overflow",[248,518,396],{"class":253},[248,520,521],{"class":260},"hidden",[248,523,461],{"class":253},[248,525,527],{"class":130,"line":526},8,[248,528,529],{"class":253},"}\n",[248,531,533,536,538,541,543,546,549,551,554,556,558],{"class":130,"line":532},9,[248,534,535],{"class":260},".bar",[248,537,390],{"class":253},[248,539,540],{"class":260},"height",[248,542,396],{"class":253},[248,544,545],{"class":260},"100",[248,547,548],{"class":408},"%",[248,550,412],{"class":253},[248,552,553],{"class":260},"background",[248,555,396],{"class":253},[248,557,168],{"class":260},[248,559,437],{"class":253},[248,561,563],{"class":130,"line":562},10,[248,564,321],{"emptyLinePlaceholder":320},[248,566,568],{"class":130,"line":567},11,[248,569,571],{"class":570},"sLBg1","\u002F* Cheap: transform is handled on the compositor thread, no layout, no paint. *\u002F\n",[248,573,575,578],{"class":130,"line":574},12,[248,576,577],{"class":260},".bar--transform",[248,579,445],{"class":253},[248,581,583,586,588,590,592],{"class":130,"line":582},13,[248,584,585],{"class":260},"  width",[248,587,396],{"class":253},[248,589,545],{"class":260},[248,591,548],{"class":408},[248,593,461],{"class":253},[248,595,597,600,602,605,608],{"class":130,"line":596},14,[248,598,599],{"class":260},"  transform-origin",[248,601,396],{"class":253},[248,603,604],{"class":260},"left",[248,606,607],{"class":260}," center",[248,609,461],{"class":253},[248,611,613,616,619,621,624,627,630,633],{"class":130,"line":612},15,[248,614,615],{"class":260},"  animation",[248,617,618],{"class":253},": bar-scale ",[248,620,135],{"class":260},[248,622,623],{"class":408},"s",[248,625,626],{"class":260}," ease-in-out",[248,628,629],{"class":260}," infinite",[248,631,632],{"class":260}," alternate",[248,634,461],{"class":253},[248,636,638],{"class":130,"line":637},16,[248,639,529],{"class":253},[248,641,643,646,650],{"class":130,"line":642},17,[248,644,645],{"class":408},"@keyframes",[248,647,649],{"class":648},"soyes"," bar-scale",[248,651,445],{"class":253},[248,653,655,658,660,662,664,667,670,673],{"class":130,"line":654},18,[248,656,657],{"class":260},"  from",[248,659,390],{"class":253},[248,661,60],{"class":260},[248,663,396],{"class":253},[248,665,666],{"class":260},"scaleX",[248,668,669],{"class":253},"(",[248,671,672],{"class":260},".15",[248,674,675],{"class":253},"); }\n",[248,677,679,682,685,687,689,691,693,695],{"class":130,"line":678},19,[248,680,681],{"class":260},"  to",[248,683,684],{"class":253},"   { ",[248,686,60],{"class":260},[248,688,396],{"class":253},[248,690,666],{"class":260},[248,692,669],{"class":253},[248,694,485],{"class":260},[248,696,675],{"class":253},[248,698,700],{"class":130,"line":699},20,[248,701,529],{"class":253},[248,703,705],{"class":130,"line":704},21,[248,706,321],{"emptyLinePlaceholder":320},[248,708,710],{"class":130,"line":709},22,[248,711,712],{"class":570},"\u002F* Expensive: width is a layout property, so every frame runs Layout and Paint. *\u002F\n",[248,714,716,719,721,724,727,729,731,733,735,737],{"class":130,"line":715},23,[248,717,718],{"class":260},".bar--width",[248,720,390],{"class":253},[248,722,723],{"class":260},"animation",[248,725,726],{"class":253},": bar-width ",[248,728,135],{"class":260},[248,730,623],{"class":408},[248,732,626],{"class":260},[248,734,629],{"class":260},[248,736,632],{"class":260},[248,738,437],{"class":253},[248,740,742,744,747],{"class":130,"line":741},24,[248,743,645],{"class":408},[248,745,746],{"class":648}," bar-width",[248,748,445],{"class":253},[248,750,752,754,756,758,760,763,765],{"class":130,"line":751},25,[248,753,657],{"class":260},[248,755,390],{"class":253},[248,757,232],{"class":260},[248,759,396],{"class":253},[248,761,762],{"class":260},"15",[248,764,548],{"class":408},[248,766,437],{"class":253},[248,768,770,772,774,776,778,780,782],{"class":130,"line":769},26,[248,771,681],{"class":260},[248,773,684],{"class":253},[248,775,232],{"class":260},[248,777,396],{"class":253},[248,779,545],{"class":260},[248,781,548],{"class":408},[248,783,437],{"class":253},[248,785,787],{"class":130,"line":786},27,[248,788,529],{"class":253},[36,790],{},[39,792,794],{"id":793},"the-workflow-click-by-click","The workflow, click by click",[14,796,797,801,802,805,806,809,810,813],{},[798,799,800],"strong",{},"1. Record a trace of the animation only."," Open DevTools, choose the ",[798,803,804],{},"Performance"," panel, set the ",[798,807,808],{},"CPU"," dropdown to ",[50,811,812],{},"4x slowdown"," (6x if you are targeting low-end Android), then press the record button, trigger the animation, let it run two or three cycles, and stop. Keep the recording under about five seconds — longer traces are harder to navigate and add nothing.",[14,815,816,819,820,823],{},[798,817,818],{},"2. Find the bad frames."," The ",[798,821,822],{},"Frames"," track sits under the timeline. Each frame is a rectangle; green is a frame delivered on time, yellow means partially presented, and red means dropped. Drag-select across a run of non-green frames to zoom the rest of the panel onto exactly that window.",[14,825,826,829,830,833,834,431,837,431,839,431,842,431,844,431,847,850,851,853],{},[798,827,828],{},"3. Read one frame's stack."," With the range selected, look at the ",[798,831,832],{},"Main"," track. Inside a single frame you will see nested entries in pipeline order: ",[50,835,836],{},"Recalculate Style",[50,838,143],{},[50,840,841],{},"Pre-Paint",[50,843,157],{},[50,845,846],{},"Layerize",[50,848,849],{},"Commit",". Hover any entry for its self time. A healthy compositor-driven animation shows a nearly empty main thread during the animation — the work is on the compositor and raster threads instead. The diagnostic signal is a ",[50,852,836],{}," entry repeating once per frame, because that means the style engine is being asked to produce a new computed value on every tick, which is what a main-thread animation looks like.",[14,855,856,859,860,864,865,868,869,872,873,875,876,878],{},[798,857,858],{},"4. Confirm what is repainting."," Press ",[861,862,863],"kbd",{},"Escape"," to open the drawer, choose the ",[798,866,867],{},"Rendering"," tab, and tick ",[798,870,871],{},"Paint flashing",". Green rectangles now flash over every region being repainted. Watch the animation: the ",[18,874,60],{}," bar should produce no flashing once it has started, while the ",[18,877,232],{}," bar flashes continuously. This is the fastest single check in the whole workflow, and it needs no recording.",[14,880,881,884,885,887,888,891,892,895,896,899,900,902,903,906],{},[798,882,883],{},"5. Check layer promotion."," In the same ",[798,886,867],{}," tab, tick ",[798,889,890],{},"Layer borders",". Composited layers get an orange border, and tiles within them get a blue-grey grid. An element you expected to be promoted but that has no border is not on its own layer, which means its animation cannot be composited. For detail, open the ",[798,893,894],{},"Layers"," panel (via the ⋮ menu → ",[798,897,898],{},"More tools"," → ",[798,901,894],{},"), click a layer, and read the sidebar: it reports the layer's memory estimate and, most usefully, the ",[798,904,905],{},"compositing reasons"," — the exact rule that caused promotion, or the absence of one.",[14,908,909,912,913,915,916,919,920,923,924,926],{},[798,910,911],{},"6. Attribute the cost."," Back in the Performance trace, select a ",[50,914,143],{}," entry and read the summary pane's ",[798,917,918],{},"Nodes that need layout"," count and the ",[50,921,922],{},"first layout invalidation"," backtrace, which names the property that dirtied it. For paint cost, select a ",[50,925,157],{}," entry and check its area — a paint covering far more than the animated element usually means the element is not isolated and is dragging its siblings into the repaint.",[14,928,929,932,933,935,936,940],{},[798,930,931],{},"7. Fix, then re-record the same trace."," Change one thing, record the same interaction with the same throttling, and compare frame colours. Optimisations applied without a second recording are guesses; this is also where you verify that a ",[18,934,20],{}," hint helped rather than just added layers, which is covered in ",[27,937,939],{"href":938},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fwill-change-and-the-compositor-thread\u002F","will-change and the compositor thread",".",[36,942],{},[39,944,946],{"id":945},"the-key-technique-spotting-an-animation-that-fell-off-the-compositor","The key technique: spotting an animation that fell off the compositor",[14,948,949,950,952,953,956,957,960,961,963],{},"An animation of ",[18,951,60],{}," or ",[18,954,955],{},"opacity"," ",[50,958,959],{},"should"," be composited, but eligibility is checked at runtime and can be lost. The tell is always the same: per-frame ",[50,962,836],{}," entries in the Main track during an animation that has no business touching the main thread. When you see that, work through the usual causes in order.",[14,965,966,967,970,971,973,974,977,978,981,982,984,985,988,989,940],{},"The most common is a second property in the same rule. ",[18,968,969],{},"transition: transform 300ms, height 300ms"," cannot be composited as a unit, because ",[18,972,540],{}," requires layout — the whole animation is demoted. Split them or drop the layout property. Next is an ancestor that forces the element's content into its parent's layer, typically an animated ",[18,975,976],{},"filter"," or a ",[18,979,980],{},"clip-path"," higher up the tree. Then there is layer explosion: if a page has promoted hundreds of elements, the compositor may decline further promotion under memory pressure, and the Layers panel's memory estimate will show why. Finally, an animation driven by class changes in a script that also reads layout properties will interleave forced synchronous layouts, which show up in the trace as a distinctive purple ",[50,983,143],{}," entry nested ",[50,986,987],{},"inside"," a scripting task — the classic layout thrash signature, and a strong argument for keeping the animation declarative, as discussed in ",[27,990,992],{"href":991},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api\u002Fwhen-to-use-javascript-animation\u002F","when to use JavaScript animation",[36,994],{},[39,996,998],{"id":997},"variation-the-animations-panel-and-reduced-motion-verification","Variation: the Animations panel and reduced-motion verification",[14,1000,1001,1002,1005,1006,899,1008,1010,1011,1013,1014,1017,1018,1022],{},"Two more drawer tabs are worth knowing. The ",[798,1003,1004],{},"Animations"," panel (⋮ → ",[798,1007,898],{},[798,1009,1004],{},") captures animation groups as they fire and lets you replay them at 25% or 10% speed, drag the timing bars, and edit keyframe offsets live — invaluable for judging whether an easing curve feels wrong rather than whether it is slow. And in the ",[798,1012,867],{}," tab, the ",[798,1015,1016],{},"Emulate CSS media feature prefers-reduced-motion"," dropdown forces the reduced state so you can confirm your guard actually collapses the motion; pair that check with the recipes in ",[27,1019,1021],{"href":1020},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Freducing-motion-preferences-in-css\u002F","reducing motion preferences in CSS",". A guard that is never tested is a guard that quietly stops working after the next refactor.",[36,1024],{},[39,1026,1028],{"id":1027},"browser-support-note","Browser support note",[14,1030,1031,1032,1034,1035,431,1038,1041,1042,1045,1046,1049,1050,1053,1054,1057,1058,1060],{},"The workflow above describes current Chrome and Edge, where the Performance panel's Frames track and compositing-reasons sidebar are in their present form; older releases carry the same information under slightly different labels. Firefox offers the same analysis through its ",[798,1033,804],{}," profiler, whose markers include ",[50,1036,1037],{},"Styles",[50,1039,1040],{},"Reflow",", and ",[50,1043,1044],{},"Rasterize",", with paint flashing available as a toolbox setting and a ",[50,1047,1048],{},"Paint Flashing"," toggle in the Firefox developer tools settings pane. Safari's Web Inspector uses a ",[798,1051,1052],{},"Timelines"," tab: the ",[50,1055,1056],{},"Rendering Frames"," timeline gives the per-frame breakdown, the ",[50,1059,894],{}," sidebar in the Elements tab lists composited layers with their memory cost, and the Graphics section of Web Inspector's settings enables layer border display. The concepts transfer unchanged between all three — only the panel names differ.",[36,1062],{},[39,1064,1066],{"id":1065},"faq","FAQ",[14,1068,1069,1072,1073,1075,1076,952,1078,1080],{},[798,1070,1071],{},"How do I tell whether an animation is running on the compositor?","\nRecord it in the Performance panel and inspect a frame from the middle of the animation. A compositor-driven animation leaves the main thread almost empty, while a main-thread one shows a ",[50,1074,836],{}," entry followed by ",[50,1077,143],{},[50,1079,157],{}," on every single frame.",[14,1082,1083,1086,1087,952,1089,1091],{},[798,1084,1085],{},"What does paint flashing actually tell me?","\nIt highlights in green every region the browser repaints. A well-behaved ",[18,1088,60],{},[18,1090,955],{}," animation should produce no flashing once it has started, so a green rectangle pulsing over the animating element means you are repainting every frame.",[14,1093,1094,1097],{},[798,1095,1096],{},"Why does my animation profile fine on a desktop but stutter on a phone?","\nDesktop machines have enough headroom to absorb layout and paint work that a mobile CPU cannot. Use the CPU throttling dropdown at 4x or 6x slowdown, which surfaces the long tasks that only appear on slower hardware.",[14,1099,1100,1103],{},[798,1101,1102],{},"Do Firefox and Safari have equivalents to these panels?","\nYes. Firefox's Performance profiler exposes the same style, reflow and rasterise markers plus a paint flashing toggle in its settings, and Safari's Web Inspector provides a Timelines tab with a Rendering Frames timeline and a Layers sidebar showing per-layer memory.",[36,1105],{},[39,1107,1109],{"id":1108},"related","Related",[1111,1112,1113,1119,1126,1131,1137],"ul",{},[1114,1115,1116,1118],"li",{},[27,1117,30],{"href":29}," — the parent guide to compositing and animation cost.",[1114,1120,1121,1125],{},[27,1122,1124],{"href":1123},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Foptimizing-css-animations-for-60fps\u002F","Optimizing CSS animations for 60fps"," — the fixes to apply once profiling has named the stage.",[1114,1127,1128,1130],{},[27,1129,939],{"href":938}," — verify layer promotion hints with the Layers panel.",[1114,1132,1133,1136],{},[27,1134,1135],{"href":991},"When to use JavaScript animation"," — the tradeoff a layout-thrash trace usually points to.",[1114,1138,1139,1143],{},[27,1140,1142],{"href":1141},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Faspect-ratio-for-responsive-media\u002F","Aspect ratio for responsive media"," — remove the layout instability that makes traces hard to read in the first place.",[1145,1146,1147],"style",{},"html pre.shiki code .suds8, html code.shiki .suds8{--shiki-default:#0E1116;--shiki-dark:#F0F3F6}html pre.shiki code .sne4z, html code.shiki .sne4z{--shiki-default:#024C1A;--shiki-dark:#72F088}html pre.shiki code .s-5SL, html code.shiki .s-5SL{--shiki-default:#023B95;--shiki-dark:#91CBFF}html pre.shiki code .sT6z2, html code.shiki .sT6z2{--shiki-default:#032563;--shiki-dark:#ADDCFF}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 .sHUrx, html code.shiki .sHUrx{--shiki-default:#A0111F;--shiki-dark:#FF9492}html pre.shiki code .sLBg1, html code.shiki .sLBg1{--shiki-default:#66707B;--shiki-dark:#BDC4CC}html pre.shiki code .soyes, html code.shiki .soyes{--shiki-default:#702C00;--shiki-dark:#FFB757}",{"title":244,"searchDepth":279,"depth":279,"links":1149},[1150,1151,1152,1153,1154,1155,1156,1157,1158],{"id":41,"depth":279,"text":42},{"id":77,"depth":279,"text":78},{"id":225,"depth":279,"text":226},{"id":793,"depth":279,"text":794},{"id":945,"depth":279,"text":946},{"id":997,"depth":279,"text":998},{"id":1027,"depth":279,"text":1028},{"id":1065,"depth":279,"text":1066},{"id":1108,"depth":279,"text":1109},"A click-by-click DevTools workflow for animation performance: paint flashing, layer borders, the Layers panel, and reading Style, Layout and Paint in a frame.","md",{"pageTitle":1162,"datePublished":1163,"dateModified":1163,"faq":1164},"Profiling animations in DevTools","2026-07-20",[1165,1167,1169,1171],{"q":1071,"a":1166},"Record it in the Performance panel and inspect a frame in the middle of the animation. A compositor-driven animation shows almost nothing on the main thread during the animation, while a main-thread one shows a Recalculate Style entry followed by Layout or Paint on every frame.",{"q":1085,"a":1168},"It highlights in green every region the browser repaints. A well-behaved transform or opacity animation should produce no flashing at all once it has started, so any repeated green rectangle over the animating element means you are repainting each frame.",{"q":1096,"a":1170},"Desktop machines have enough headroom to absorb layout and paint work that a mobile CPU cannot. Use the CPU throttling dropdown in the Performance panel at 4x or 6x slowdown, which surfaces the long tasks that only appear on slower hardware.",{"q":1102,"a":1172},"Yes. Firefox has a Performance profiler with the same style, layout and paint markers plus a paint flashing toggle in its settings, and Safari's Web Inspector has a Timelines tab with a Rendering Frames timeline and a Layers sidebar.","\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fprofiling-animations-in-devtools",{"title":5,"description":1159},"css-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fprofiling-animations-in-devtools\u002Findex","rYUuvS2vTAN1UxSeYUIhtlMVINY5A6_LScTZS93Adxo",[1178,1181,1184,1187,1190,1193,1196,1199,1202,1205,1208,1211,1214,1217,1220,1223,1226,1229,1232,1235,1238,1241,1244,1247,1250,1253,1256,1259,1262,1265,1268,1271,1274,1277,1280,1283,1286,1287,1290,1293,1296,1299,1302,1305,1308,1311,1314,1317,1320,1323,1326,1329,1332,1335,1338,1341,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],{"path":1179,"title":1180},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fcreating-accessible-focus-indicators","Creating Accessible Focus Indicators: Building a Ring That Survives Any Background",{"path":1182,"title":1183},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations","Accessibility in CSS Animations: Patterns, Specs & Best Practices",{"path":1185,"title":1186},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fprefers-reduced-motion-recipes","prefers-reduced-motion Recipes: A Reduction for Every Common Effect",{"path":1188,"title":1189},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Freducing-motion-preferences-in-css","Reducing Motion Preferences in CSS: How the Setting Becomes a Media Feature",{"path":1191,"title":1192},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Ftarget-size-and-pointer-accessibility","Target Size and Pointer Accessibility: Meeting 2.5.8 Without Redesigning",{"path":1194,"title":1195},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fvestibular-safe-animation-patterns","Vestibular-Safe Animation Patterns: Why Some Motion Makes People Sick",{"path":1197,"title":1198},"\u002Fcss-only-micro-interactions-animations\u002Faccessibility-in-css-animations\u002Fwcag-motion-success-criteria","WCAG Motion Success Criteria: What Each One Actually Requires",{"path":1200,"title":1201},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fcontainer-query-hover-affordances","Container Query Hover Affordances: When Narrow Means Persistent, Not Hidden",{"path":1203,"title":1204},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion","Container-Aware Motion: Animation Sized by the Space a Component Actually Has",{"path":1206,"title":1207},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fmotion-that-scales-with-container-size","Motion That Scales with Container Size: cqi, cqb, and Derived Durations",{"path":1209,"title":1210},"\u002Fcss-only-micro-interactions-animations\u002Fcontainer-aware-motion\u002Fsuppressing-motion-in-small-containers","Suppressing Motion in Small Containers: Deliberately Animating Nothing",{"path":1212,"title":1213},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api","CSS Animation vs the Web Animations API: A Decision Guide",{"path":1215,"title":1216},"\u002Fcss-only-micro-interactions-animations\u002Fcss-animation-vs-web-animations-api\u002Fwhen-to-use-javascript-animation","When to Use JavaScript Instead of CSS for Animation",{"path":1218,"title":1219},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fanimating-custom-properties-with-at-property","Animating Custom Properties with @property: Typed Variables That Interpolate",{"path":1221,"title":1222},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Ffluid-spacing-tokens-driving-transition-durations","Fluid Spacing Tokens That Drive Transition Durations",{"path":1224,"title":1225},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture","CSS Custom Properties Architecture: Scalable Design Systems & Dynamic UI",{"path":1227,"title":1228},"\u002Fcss-only-micro-interactions-animations\u002Fcss-custom-properties-architecture\u002Fregistered-properties-and-type-safety","Registered Properties and Type Safety: @property as a Contract for Design Tokens",{"path":1230,"title":1231},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fcss-transition-timing-functions","CSS Transition Timing Functions: ease, cubic-bezier(), steps() and linear()",{"path":1233,"title":1234},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals","CSS Transition Fundamentals: Architecture, Performance & Patterns",{"path":1236,"title":1237},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Fstarting-style-entry-animations","@starting-style: Animating an Element's Very First Style Change",{"path":1239,"title":1240},"\u002Fcss-only-micro-interactions-animations\u002Fcss-transition-fundamentals\u002Ftransitioning-display-with-allow-discrete","Transitioning display with transition-behavior: allow-discrete and @starting-style",{"path":1242,"title":1243},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Faccessible-css-only-tooltips","Accessible CSS-Only Tooltips and Hover Cards With  and ",{"path":1245,"title":1246},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Ffocus-visible-vs-focus-polyfill-alternatives"," vs :focus: Why It Replaced the Focus-Ring Polyfill",{"path":1248,"title":1249},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Ffocus-within-form-patterns"," Form Patterns: Styling a Group From the Field Inside It",{"path":1251,"title":1252},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design","Hover & Focus State Design: Spec-Compliant Patterns for Modern UIs",{"path":1254,"title":1255},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Fpointer-and-hover-media-queries","Pointer and Hover Media Queries: Gating Affordances by Input Capability",{"path":1257,"title":1258},"\u002Fcss-only-micro-interactions-animations\u002Fhover-focus-state-design\u002Fsmooth-hover-effects-without-javascript","Smooth Hover Effects Without JavaScript: CSS-Only Patterns for Modern UI",{"path":1260,"title":1261},"\u002Fcss-only-micro-interactions-animations","CSS-Only Micro-Interactions & Animations: Architecture, Performance & Implementation",{"path":1263,"title":1264},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcontainer-query-triggered-keyframe-animations","Container-Query-Triggered Keyframe Animations: Animate Differently per Available Space",{"path":1266,"title":1267},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcss-only-accordions-and-disclosure","CSS-Only Accordions and Disclosure Widgets with details and summary",{"path":1269,"title":1270},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcss-only-loading-spinners-and-skeletons","CSS-Only Loading Spinners and Skeleton Shimmer Screens with @keyframes",{"path":1272,"title":1273},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fcss-only-toggle-switches-and-checkboxes","CSS-Only Toggle Switches and Checkboxes That Keep the Native Input",{"path":1275,"title":1276},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns","Keyframe Animation Patterns: Spec-Compliant Architectures for Modern UIs",{"path":1278,"title":1279},"\u002Fcss-only-micro-interactions-animations\u002Fkeyframe-animation-patterns\u002Fstaggered-list-animations-with-custom-properties","Staggered List Animations Using --i Index Custom Properties",{"path":1281,"title":1282},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration","Performance & GPU Acceleration in CSS: A Developer’s Blueprint",{"path":1284,"title":1285},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Foptimizing-css-animations-for-60fps","Optimizing CSS Animations for 60fps: Budgeting the Frame",{"path":1173,"title":5},{"path":1288,"title":1289},"\u002Fcss-only-micro-interactions-animations\u002Fperformance-gpu-acceleration\u002Fwill-change-and-the-compositor-thread","will-change and the Compositor Thread: Layer Promotion Without the Footguns",{"path":1291,"title":1292},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations","Scroll-Driven Animations: Binding Motion to Scroll Position in Pure CSS",{"path":1294,"title":1295},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-driven-animation-fallbacks","Shipping Scroll-Driven Animations Without Breaking Anything",{"path":1297,"title":1298},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-progress-bar-without-javascript","A Reading Progress Bar Driven by scroll(root)",{"path":1300,"title":1301},"\u002Fcss-only-micro-interactions-animations\u002Fscroll-driven-animations\u002Fscroll-triggered-reveal-animations","Reveal-on-Scroll with view() and animation-range",{"path":1303,"title":1304},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers","View Transitions for CSS Developers: the Pseudo-Element Tree, Snapshots, and Named Elements",{"path":1306,"title":1307},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fsame-document-view-transitions","Writing a Same-Document View Transition: the CSS You Actually Author",{"path":1309,"title":1310},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transition-names-shared-elements","view-transition-name and Shared Elements: Morphing a Thumbnail into a Hero",{"path":1312,"title":1313},"\u002Fcss-only-micro-interactions-animations\u002Fview-transitions-for-css-developers\u002Fview-transitions-with-reduced-motion","Honouring prefers-reduced-motion in View Transitions",{"path":1315,"title":1316},"\u002F","Modern CSS Layouts & Micro-Interactions",{"path":1318,"title":1319},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioned-tooltips","Anchor-Positioned Tooltips: Tethering, Flipping, and Getting the Semantics Right",{"path":1321,"title":1322},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fanchor-positioning-fallbacks","Anchor Positioning Fallbacks: A Graceful Floor for Older Browser Versions",{"path":1324,"title":1325},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays","CSS Anchor Positioning and Overlays: Tethering Elements Without JavaScript",{"path":1327,"title":1328},"\u002Fmastering-container-queries-responsive-layouts\u002Fanchor-positioning-and-overlays\u002Fpopover-attribute-and-css-styling","The popover Attribute: Top-Layer Overlays With No JavaScript",{"path":1330,"title":1331},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Ffeature-detection-with-supports","Feature Detection with @supports: Syntax, Semantics, and the Traps",{"path":1333,"title":1334},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks\u002Fhandling-container-query-fallbacks-for-older-browsers","Handling Container Query Fallbacks for Older Browsers",{"path":1336,"title":1337},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-fallbacks","Container Query Fallbacks: Spec-Compliant CSS Strategies for Legacy Browsers",{"path":1339,"title":1340},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-query-units-cqi-cqb-explained","Container Query Units Explained: cqi, cqb, cqw, cqh, cqmin and cqmax",{"path":1342,"title":1343},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-type-size-vs-inline-size","Choosing container-type: inline-size, size, or normal",{"path":1345,"title":1346},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fcontainer-vs-media-queries-comparison","Container vs Media Queries: Choosing the Right Reference Box",{"path":1348,"title":1349},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fhow-to-use-container-queries-in-production","How to Use Container Queries in Production Without a Rewrite",{"path":1351,"title":1352},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics","Container Query Syntax Basics",{"path":1354,"title":1355},"\u002Fmastering-container-queries-responsive-layouts\u002Fcontainer-query-syntax-basics\u002Fnesting-and-naming-container-queries","Nesting and Naming Container Queries: Targeting the Right Ancestor",{"path":1357,"title":1358},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fauto-fit-minmax-responsive-grids","Responsive Grids with repeat(auto-fit, minmax())",{"path":1360,"title":1361},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fbuilding-a-dashboard-with-subgrid","Building a Responsive Dashboard Where Cards Align with Subgrid",{"path":1363,"title":1364},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fholy-grail-layout-with-grid","The Holy-Grail Layout with CSS Grid and Container Queries",{"path":1366,"title":1367},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts","CSS Grid and Subgrid Layouts for Responsive Interfaces",{"path":1369,"title":1370},"\u002Fmastering-container-queries-responsive-layouts\u002Fcss-grid-and-subgrid-layouts\u002Fsubgrid-vs-nested-grid","Subgrid vs an Independently Nested Grid",{"path":1372,"title":1373},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Fclamp-vs-media-query-typography","clamp() Fluid Type vs Media-Query Step Typography: Tradeoffs and Anatomy",{"path":1375,"title":1376},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-space-scale-with-clamp","Building a Fluid Spacing Scale with clamp() and Container Units",{"path":1378,"title":1379},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-type-accessibility-and-zoom","Fluid Type, Accessibility and Zoom: The vw-Only Trap",{"path":1381,"title":1382},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp\u002Ffluid-typography-without-javascript","Fluid Typography Without JavaScript: A Precision CSS Reference",{"path":1384,"title":1385},"\u002Fmastering-container-queries-responsive-layouts\u002Ffluid-typography-with-clamp","Fluid Typography with clamp(): A Practical Guide for Modern CSS",{"path":1387,"title":1388},"\u002Fmastering-container-queries-responsive-layouts","Mastering Container Queries & Responsive Layouts",{"path":1390,"title":1391},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Faspect-ratio-for-responsive-media","Using aspect-ratio for Responsive Media and Preventing Layout Shift",{"path":1393,"title":1394},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques","Intrinsic Sizing Techniques: Modern CSS Layouts for Responsive UI",{"path":1396,"title":1397},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fmin-max-fit-content-explained","min-content, max-content, and fit-content() Explained",{"path":1399,"title":1400},"\u002Fmastering-container-queries-responsive-layouts\u002Fintrinsic-sizing-techniques\u002Fpreventing-flex-and-grid-overflow","The min-width: auto Trap in Flex and Grid Layouts",{"path":1402,"title":1403},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-for-reset-and-tokens","Cascade Layers for Reset and Design Tokens",{"path":1405,"title":1406},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies\u002Fcascade-layers-vs-specificity-hacks","Cascade Layers vs Specificity Hacks: Ordering Instead of Escalating",{"path":1408,"title":1409},"\u002Fmastering-container-queries-responsive-layouts\u002Fmodern-css-reset-strategies","Modern CSS Reset Strategies: A Spec-Compliant Foundation",{"path":1411,"title":1412},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fbuilding-responsive-cards-with-container-queries","Building Responsive Cards with Container Queries: A Production-Ready Guide",{"path":1414,"title":1415},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-data-tables","Container Query Data Tables: Reflowing Tables to Cards",{"path":1417,"title":1418},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fcontainer-query-sidebar-layouts","Container Query Sidebar Layouts That Travel Between Contexts",{"path":1420,"title":1421},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns","Responsive Component Patterns: Architecture & Implementation",{"path":1423,"title":1424},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-forms-with-container-queries","Responsive Forms with Container Queries: Reflow Without Losing the Wiring",{"path":1426,"title":1427},"\u002Fmastering-container-queries-responsive-layouts\u002Fresponsive-component-patterns\u002Fresponsive-navigation-without-media-queries","Responsive Navigation Without Media Queries Using Container Queries",{"path":1429,"title":1430},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002Fcontainer-style-query-theming","Container Style Query Theming: One Token Instead of a Variant Class Matrix",{"path":1432,"title":1433},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state","Style Queries and Container State: Token-Driven Component Variants",{"path":1435,"title":1436},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002Fstyle-queries-with-custom-properties","Style Queries With Custom Properties: Declaring, Inheriting, and Matching Tokens",{"path":1438,"title":1439},"\u002Fmastering-container-queries-responsive-layouts\u002Fstyle-queries-and-container-state\u002Fstyle-query-fallbacks-and-support","Style Query Fallbacks and Support: Designing for Older Browser Versions",1784566157979]