[{"data":1,"prerenderedAt":984},["ShallowReactive",2],{"content:\u002Frendering-css-performance\u002Fanimation-and-compositing-performance\u002Fwill-change-overuse-and-layer-explosion":3,"surroundings:\u002Frendering-css-performance\u002Fanimation-and-compositing-performance\u002Fwill-change-overuse-and-layer-explosion":975},{"id":4,"title":5,"body":6,"description":955,"extension":956,"meta":957,"navigation":968,"path":969,"seo":970,"stem":973,"__hash__":974},"content\u002Frendering-css-performance\u002Fanimation-and-compositing-performance\u002Fwill-change-overuse-and-layer-explosion\u002Findex.md","will-change Overuse and Layer Explosion",{"type":7,"value":8,"toc":937},"minimark",[9,13,37,44,137,142,185,189,195,203,209,215,219,224,233,237,381,385,434,438,449,593,597,604,608,624,698,702,708,712,729,733,762,766,772,778,784,790,794,806,815,827,836,845,854,863,875,884,896,900,922,927,930,933],[10,11,5],"h1",{"id":12},"will-change-overuse-and-layer-explosion",[14,15,16,17,22,23,27,28,32,33,36],"p",{},"This guide is part of ",[18,19,21],"a",{"href":20},"\u002Frendering-css-performance\u002Fanimation-and-compositing-performance\u002F","Animation & Compositing Performance",", within ",[18,24,26],{"href":25},"\u002Frendering-css-performance\u002F","Rendering & CSS Performance",". ",[29,30,31],"code",{},"will-change: transform"," tells the browser that an element is about to be transformed, so it can promote the element to its own compositing layer in advance and avoid a hitch when the animation starts. It works, so it spreads: onto every card, every button, every list item, sometimes onto ",[29,34,35],{},"*"," in a global stylesheet. Each promoted element gets its own layer, with its own GPU memory for rasterised tiles. Hundreds or thousands of layers consume large amounts of memory, slow down compositing, and on low-end phones can make the page slower, not faster.",[14,38,39,40,43],{},"Layers can also multiply implicitly: when an element overlaps a composited layer, the browser may need to promote it too, so that it draws in the correct order (\"overlap\" promotion). One ",[29,41,42],{},"will-change"," on a background element can cascade into many layers for everything above it.",[14,45,46],{},[47,48,54,55,54,62,54,66,54,69,54,78,54,84,54,91,54,99,54,104,54,108,54,112,54,116,54,120,54,127,54,131,54],"svg",{"viewBox":49,"width":50,"role":51,"ariaLabel":52,"style":53},"0 0 760 189","100%","img","Bar chart comparing estimated layer memory for a product grid with blanket will-change and with targeted promotion.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[56,57],"rect",{"className":58,"x":60,"y":60,"width":50,"height":50,"fill":61},[59],"svg-canvas","0","#ffffff",[63,64,65],"title",{},"GPU memory for compositing layers on a product grid page",[67,68,52],"desc",{},[56,70],{"x":71,"y":71,"width":72,"height":73,"rx":74,"fill":75,"stroke":76,"style":77},"1","758","187","10","none","currentColor","stroke-opacity:0.18",[79,80,65],"text",{"x":81,"y":82,"fill":76,"style":83},"28.0","34.0","font-size:16px;font-weight:700",[79,85,90],{"x":86,"y":87,"fill":76,"style":88,"textAnchor":89},"238.7","70.0","font-size:13px","end","will-change on every card (96 layers)",[56,92],{"x":93,"y":94,"width":95,"height":96,"rx":97,"fill":75,"stroke":76,"style":98},"250.7","56.0","340.3","19","3","fill-opacity:0.7;stroke-opacity:0.35",[79,100,103],{"x":101,"y":87,"fill":76,"style":102},"597.0","font-size:12px;font-weight:600","212MB",[79,105,107],{"x":86,"y":106,"fill":76,"style":88,"textAnchor":89},"101.0","Overlap-promoted badges added",[56,109],{"x":93,"y":110,"width":111,"height":96,"rx":97,"fill":75,"stroke":76,"style":98},"87.0","417.3",[79,113,115],{"x":114,"y":106,"fill":76,"style":102},"674.0","260MB",[79,117,119],{"x":86,"y":118,"fill":76,"style":88,"textAnchor":89},"132.0","Promotion only while hovering",[56,121],{"x":93,"y":122,"width":123,"height":96,"rx":97,"fill":124,"stroke":125,"style":126},"118.0","54.6","#ffc300","#b8860b","fill-opacity:0.7;stroke-opacity:0.9",[79,128,130],{"x":129,"y":118,"fill":76,"style":102},"311.3","34MB",[79,132,136],{"x":81,"y":133,"fill":134,"style":135},"167.0","#51617a","font-size:12.5px","3x DPR phone viewport; values from the Layers panel.",[138,139,141],"h2",{"id":140},"rapid-diagnosis","Rapid Diagnosis",[143,144,145,153,159,179],"ul",{},[146,147,148,152],"li",{},[149,150,151],"strong",{},"Open the Layers panel"," (DevTools → More tools → Layers) and check the layer count and total memory estimate.",[146,154,155,158],{},[149,156,157],{},"Enable Layer borders"," in the Rendering drawer to see layers outlined on the page.",[146,160,161,164,165,167,168,167,171,174,175,178],{},[149,162,163],{},"Search CSS"," for ",[29,166,42],{},", ",[29,169,170],{},"translateZ(0)",[29,172,173],{},"translate3d(0,0,0)"," and ",[29,176,177],{},"backface-visibility: hidden"," — common promotion hacks.",[146,180,181,184],{},[149,182,183],{},"Check each layer's compositing reason"," in the Layers panel details (\"will-change\", \"overlaps other composited content\", \"active animation\").",[138,186,188],{"id":187},"root-cause-analysis","Root Cause Analysis",[14,190,191,194],{},[149,192,193],{},"1. Blanket will-change."," Applied to many elements permanently \"just in case\".",[14,196,197,54,200,202],{},[149,198,199],{},"2. Legacy promotion hacks.",[29,201,170],{}," used to fix flicker years ago, still in the CSS.",[14,204,205,208],{},[149,206,207],{},"3. Overlap promotion."," Elements above a composited layer get promoted to preserve stacking order.",[14,210,211,214],{},[149,212,213],{},"4. Large layers."," Full-page or very tall promoted elements consume memory proportional to their area.",[138,216,218],{"id":217},"step-by-step-resolution","Step-by-Step Resolution",[220,221,223],"h3",{"id":222},"_1-audit-and-remove-permanent-promotion","1. Audit and remove permanent promotion",[14,225,226,227,229,230,232],{},"Remove ",[29,228,42],{}," from elements that do not animate, and remove ",[29,231,170],{}," hacks unless a specific rendering bug requires them (test after removal).",[220,234,236],{"id":235},"_2-promote-only-shortly-before-and-during-animation","2. Promote only shortly before and during animation",[238,239,244],"pre",{"className":240,"code":241,"language":242,"meta":243,"style":243},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","const panel = document.querySelector('.drawer');\nbutton.addEventListener('pointerenter', () => { panel.style.willChange = 'transform'; });\nbutton.addEventListener('click', () => panel.classList.toggle('open'));\npanel.addEventListener('transitionend', () => { panel.style.willChange = 'auto'; });\n\u002F\u002F trade-off: promoting on hover gives the browser time to prepare the layer, but\n\u002F\u002F touch devices have no hover; promote on pointerdown or accept a small hitch.\n","javascript","",[29,245,246,280,312,342,368,375],{"__ignoreMap":243},[247,248,251,255,259,262,266,270,273,277],"span",{"class":249,"line":250},"line",1,[247,252,254],{"class":253},"sPARh","const",[247,256,258],{"class":257},"sPXB4"," panel",[247,260,261],{"class":253}," =",[247,263,265],{"class":264},"saISM"," document.",[247,267,269],{"class":268},"smZ65","querySelector",[247,271,272],{"class":264},"(",[247,274,276],{"class":275},"sZ8jY","'.drawer'",[247,278,279],{"class":264},");\n",[247,281,283,286,289,291,294,297,300,303,306,309],{"class":249,"line":282},2,[247,284,285],{"class":264},"button.",[247,287,288],{"class":268},"addEventListener",[247,290,272],{"class":264},[247,292,293],{"class":275},"'pointerenter'",[247,295,296],{"class":264},", () ",[247,298,299],{"class":253},"=>",[247,301,302],{"class":264}," { panel.style.willChange ",[247,304,305],{"class":253},"=",[247,307,308],{"class":275}," 'transform'",[247,310,311],{"class":264},"; });\n",[247,313,315,317,319,321,324,326,328,331,334,336,339],{"class":249,"line":314},3,[247,316,285],{"class":264},[247,318,288],{"class":268},[247,320,272],{"class":264},[247,322,323],{"class":275},"'click'",[247,325,296],{"class":264},[247,327,299],{"class":253},[247,329,330],{"class":264}," panel.classList.",[247,332,333],{"class":268},"toggle",[247,335,272],{"class":264},[247,337,338],{"class":275},"'open'",[247,340,341],{"class":264},"));\n",[247,343,345,348,350,352,355,357,359,361,363,366],{"class":249,"line":344},4,[247,346,347],{"class":264},"panel.",[247,349,288],{"class":268},[247,351,272],{"class":264},[247,353,354],{"class":275},"'transitionend'",[247,356,296],{"class":264},[247,358,299],{"class":253},[247,360,302],{"class":264},[247,362,305],{"class":253},[247,364,365],{"class":275}," 'auto'",[247,367,311],{"class":264},[247,369,371],{"class":249,"line":370},5,[247,372,374],{"class":373},"sjfSM","\u002F\u002F trade-off: promoting on hover gives the browser time to prepare the layer, but\n",[247,376,378],{"class":249,"line":377},6,[247,379,380],{"class":373},"\u002F\u002F touch devices have no hover; promote on pointerdown or accept a small hitch.\n",[220,382,384],{"id":383},"_3-scope-will-change-in-css-to-active-states","3. Scope will-change in CSS to active states",[238,386,390],{"className":387,"code":388,"language":389,"meta":243,"style":243},"language-css shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast",".card:hover, .card:focus-within { will-change: transform; }\n.carousel.is-dragging .slide { will-change: transform; }\n\u002F* trade-off: the first hover still pays the promotion cost; for most cards\n   this is negligible compared with permanent promotion of all cards. *\u002F\n","css",[29,391,392,410,424,429],{"__ignoreMap":243},[247,393,394,397,399,402,405,407],{"class":249,"line":250},[247,395,396],{"class":257},".card:hover",[247,398,167],{"class":264},[247,400,401],{"class":257},".card:focus-within",[247,403,404],{"class":264}," { ",[247,406,42],{"class":257},[247,408,409],{"class":264},": transform; }\n",[247,411,412,415,418,420,422],{"class":249,"line":282},[247,413,414],{"class":257},".carousel.is-dragging",[247,416,417],{"class":257}," .slide",[247,419,404],{"class":264},[247,421,42],{"class":257},[247,423,409],{"class":264},[247,425,426],{"class":249,"line":314},[247,427,428],{"class":373},"\u002F* trade-off: the first hover still pays the promotion cost; for most cards\n",[247,430,431],{"class":249,"line":344},[247,432,433],{"class":373},"   this is negligible compared with permanent promotion of all cards. *\u002F\n",[220,435,437],{"id":436},"_4-avoid-overlap-cascades","4. Avoid overlap cascades",[14,439,440,441,444,445,448],{},"Give promoted elements a high ",[29,442,443],{},"z-index"," or isolate them (",[29,446,447],{},"isolation: isolate"," on a parent), so fewer elements need promotion to preserve order; check the Layers panel for \"overlaps\" reasons.",[14,450,451],{},[47,452,54,455,54,458,54,461,54,463,54,480,54,483,54,485,54,491,54,498,54,502,54,506,54,514,54,521,54,525,54,530,54,533,54,537,54,540,54,543,54,546,54,549,54,552,54,555,54,558,54,562,54,564,54,567,54,570,54,573,54,577,54,580,54,585,54,589,54],{"viewBox":453,"width":50,"role":51,"ariaLabel":454,"style":53},"0 0 760 341","Decision sequence for whether to add will-change to an element.",[56,456],{"className":457,"x":60,"y":60,"width":50,"height":50,"fill":61},[59],[63,459,460],{},"Should this element have will-change?",[67,462,454],{},[464,465,466],"defs",{},[467,468,475],"marker",{"id":469,"viewBox":470,"refX":471,"refY":472,"markerWidth":473,"markerHeight":473,"orient":474},"fac5e4fcbd","0 0 10 10","9","5","7","auto-start-reverse",[476,477],"path",{"d":478,"fill":76,"style":479},"M0 0 L10 5 L0 10 z","fill-opacity:0.7",[56,481],{"x":71,"y":71,"width":72,"height":482,"rx":74,"fill":75,"stroke":76,"style":77},"339",[79,484,460],{"x":81,"y":82,"fill":76,"style":83},[56,486],{"x":81,"y":94,"width":487,"height":488,"rx":489,"fill":76,"stroke":76,"style":490},"320.0","35.0","6","fill-opacity:0.06;stroke-opacity:0.4",[79,492,497],{"x":493,"y":494,"fill":76,"style":495,"textAnchor":496},"188.0","78.0","font-size:13px;font-weight:700","middle","Does it animate transform or opacity?",[56,499],{"x":500,"y":94,"width":487,"height":488,"rx":489,"fill":75,"stroke":76,"style":501},"412.0","stroke-opacity:0.35",[79,503,505],{"x":504,"y":494,"fill":76,"style":135,"textAnchor":496},"572.0","No — will-change will not help",[249,507],{"x1":508,"y1":509,"x2":510,"y2":509,"stroke":76,"strokeWidth":511,"style":512,"markerEnd":513},"348.0","73.5","410.0","1.5","stroke-opacity:0.6","url(#fac5e4fcbd)",[79,515,520],{"x":516,"y":517,"fill":518,"style":519,"textAnchor":496},"380.0","66.5","#0466c8","font-size:11.5px;font-weight:700","yes",[249,522],{"x1":493,"y1":523,"x2":493,"y2":524,"stroke":76,"strokeWidth":511,"style":512,"markerEnd":513},"91.0","125.0",[79,526,529],{"x":527,"y":528,"fill":134,"style":519},"196.0","113.0","no",[56,531],{"x":81,"y":532,"width":487,"height":488,"rx":489,"fill":76,"stroke":76,"style":490},"127.0",[79,534,536],{"x":493,"y":535,"fill":76,"style":495,"textAnchor":496},"149.0","Is there a visible hitch on the first frame?",[56,538],{"x":500,"y":532,"width":487,"height":488,"rx":489,"fill":518,"stroke":518,"style":539},"fill-opacity:0.14;stroke-opacity:0.9",[79,541,542],{"x":504,"y":535,"fill":76,"style":135,"textAnchor":496},"Promote shortly before animating",[249,544],{"x1":508,"y1":545,"x2":510,"y2":545,"stroke":76,"strokeWidth":511,"style":512,"markerEnd":513},"144.5",[79,547,520],{"x":516,"y":548,"fill":518,"style":519,"textAnchor":496},"137.5",[249,550],{"x1":493,"y1":551,"x2":493,"y2":527,"stroke":76,"strokeWidth":511,"style":512,"markerEnd":513},"162.0",[79,553,529],{"x":527,"y":554,"fill":134,"style":519},"184.0",[56,556],{"x":81,"y":557,"width":487,"height":488,"rx":489,"fill":76,"stroke":76,"style":490},"198.0",[79,559,561],{"x":493,"y":560,"fill":76,"style":495,"textAnchor":496},"220.0","Does it animate continuously (spinner, ticker)?",[56,563],{"x":500,"y":557,"width":487,"height":488,"rx":489,"fill":518,"stroke":518,"style":539},[79,565,566],{"x":504,"y":560,"fill":76,"style":135,"textAnchor":496},"Keep promoted while visible",[249,568],{"x1":508,"y1":569,"x2":510,"y2":569,"stroke":76,"strokeWidth":511,"style":512,"markerEnd":513},"215.5",[79,571,520],{"x":516,"y":572,"fill":518,"style":519,"textAnchor":496},"208.5",[249,574],{"x1":493,"y1":575,"x2":493,"y2":576,"stroke":76,"strokeWidth":511,"style":512,"markerEnd":513},"233.0","267.0",[79,578,529],{"x":527,"y":579,"fill":134,"style":519},"255.0",[56,581],{"x":81,"y":582,"width":487,"height":583,"rx":489,"fill":124,"stroke":125,"style":584},"269.0","50.0","fill-opacity:0.24;stroke-opacity:0.9",[79,586,588],{"x":493,"y":587,"fill":76,"style":135,"textAnchor":496},"290.5","Leave it out — the browser promotes during the",[79,590,592],{"x":493,"y":591,"fill":76,"style":135,"textAnchor":496},"306.5","animation",[138,594,596],{"id":595},"verification","Verification",[14,598,599,600,603],{},"Re-check the Layers panel: layer count and memory should drop. Animations should still be smooth (Frames track under throttling); if a first-frame hitch appears, add targeted promotion before that animation. On low-end Android devices, compare scrolling smoothness and memory usage (",[29,601,602],{},"chrome:\u002F\u002Fmemory-internals"," or the Performance panel's memory track) before and after.",[138,605,607],{"id":606},"worked-example-a-product-listing-page","Worked Example: A Product Listing Page",[14,609,610,611,613,614,616,617,174,620,623],{},"A fashion retailer applied ",[29,612,31],{}," to all product cards to make hover zoom smooth. On a category page with 96 cards, the Layers panel showed 220 layers (cards plus overlap-promoted sale badges) and an estimated 260MB of layer memory on a 3x DPR device. Low-end Android phones showed checkerboarding during fast scrolls and occasional tab crashes. Moving ",[29,615,42],{}," to ",[29,618,619],{},":hover",[29,621,622],{},":focus-within"," reduced layers to 12 at rest and memory to 34MB. Hover zoom remained smooth on desktop, and mobile scroll jank reports disappeared.",[14,625,626],{},[47,627,54,630,54,633,54,636,54,638,54,641,54,643,54,647,54,653,54,658,54,661,54,665,54,668,54,671,54,675,54,678,54,681,54,685,54,688,54,691,54,695,54],{"viewBox":628,"width":50,"role":51,"ariaLabel":629,"style":53},"0 0 760 318","Common compositing reasons shown in the Layers panel, from explicit hints to implicit overlap promotion.",[56,631],{"className":632,"x":60,"y":60,"width":50,"height":50,"fill":61},[59],[63,634,635],{},"Why an element gets its own layer",[67,637,629],{},[56,639],{"x":71,"y":71,"width":72,"height":640,"rx":74,"fill":75,"stroke":76,"style":77},"316",[79,642,635],{"x":81,"y":82,"fill":76,"style":83},[56,644],{"x":81,"y":94,"width":645,"height":646,"rx":489,"fill":75,"stroke":76,"style":501},"704.0","40.0",[79,648,652],{"x":649,"y":650,"fill":76,"style":495,"textAnchor":651},"42.0","80.5","start","will-change transform or opacity",[79,654,657],{"x":655,"y":650,"fill":76,"style":656,"textAnchor":651},"278.0","font-size:12px","Explicit hint from CSS or script",[56,659],{"x":81,"y":660,"width":645,"height":646,"rx":489,"fill":518,"stroke":518,"style":539},"106.0",[79,662,664],{"x":649,"y":663,"fill":76,"style":495,"textAnchor":651},"130.5","Active transform or opacity animation",[79,666,667],{"x":655,"y":663,"fill":76,"style":656,"textAnchor":651},"Promoted while it runs",[56,669],{"x":81,"y":670,"width":645,"height":646,"rx":489,"fill":76,"stroke":76,"style":490},"156.0",[79,672,674],{"x":649,"y":673,"fill":76,"style":495,"textAnchor":651},"180.5","Video, canvas, 3D transforms",[79,676,677],{"x":655,"y":673,"fill":76,"style":656,"textAnchor":651},"Composited by nature",[56,679],{"x":81,"y":680,"width":645,"height":646,"rx":489,"fill":75,"stroke":76,"style":501},"206.0",[79,682,684],{"x":649,"y":683,"fill":76,"style":495,"textAnchor":651},"230.5","Overlaps a composited layer",[79,686,687],{"x":655,"y":683,"fill":76,"style":656,"textAnchor":651},"Implicitly promoted to keep paint order",[56,689],{"x":81,"y":690,"width":645,"height":646,"rx":489,"fill":76,"stroke":76,"style":490},"256.0",[79,692,694],{"x":649,"y":693,"fill":76,"style":495,"textAnchor":651},"280.5","Fixed or sticky position",[79,696,697],{"x":655,"y":693,"fill":76,"style":656,"textAnchor":651},"Often composited for scrolling",[138,699,701],{"id":700},"large-layers-and-memory","Large Layers and Memory",[14,703,704,705,707],{},"Even a single layer can be expensive if it is large. A promoted element as tall as a long page (for example, a parallax background or a full-page wrapper with ",[29,706,42],{},") needs tiles for its whole area, multiplied by the device pixel ratio squared. Browsers rasterise layers lazily in tiles near the viewport, but memory can still spike. Avoid promoting page-sized containers; promote the smallest element that actually moves. For full-screen effects, a fixed-position element the size of the viewport is much cheaper than a page-tall one.",[138,709,711],{"id":710},"auditing-layers-in-ci","Auditing Layers in CI",[14,713,714,715,717,718,167,720,722,723,174,725,728],{},"Layer explosion tends to come back as new components copy old patterns. A lightweight guard is a stylesheet lint rule that flags ",[29,716,42],{}," outside ",[29,719,619],{},[29,721,622],{}," or explicitly named animation state classes, and flags ",[29,724,170],{},[29,726,727],{},"translate3d(0, 0, 0)"," entirely. For a runtime check, a Puppeteer script can open key pages, use the Chrome DevTools Protocol's LayerTree domain to count layers and sum their painted areas, and fail the build if either exceeds a budget. Even a rough budget — for example, fewer than 30 layers at rest on a product listing — catches the large regressions that cause mobile jank.",[138,730,732],{"id":731},"common-mistakes","Common Mistakes",[143,734,735,744,750,756],{},[146,736,737,743],{},[149,738,739,742],{},[29,740,741],{},"* { will-change: transform }"," or similar global rules."," Promotes everything.",[146,745,746,749],{},[149,747,748],{},"Leaving will-change on after animation."," Layers persist indefinitely.",[146,751,752,755],{},[149,753,754],{},"translateZ(0) hacks."," Usually unnecessary in modern browsers.",[146,757,758,761],{},[149,759,760],{},"Promoting page-sized containers."," Very large layers use lots of memory.",[138,763,765],{"id":764},"edge-cases","Edge Cases",[14,767,768,771],{},[149,769,770],{},"Continuous animations."," Spinners and tickers animate all the time; keeping them promoted is fine, but pause them when offscreen.",[14,773,774,777],{},[149,775,776],{},"Text rendering on layers."," Promoted layers may change text antialiasing; a reason to avoid promoting text-heavy elements permanently.",[14,779,780,783],{},[149,781,782],{},"Fixed-position elements."," Often composited automatically for scrolling; avoid adding will-change on top.",[14,785,786,789],{},[149,787,788],{},"Video and canvas."," Already composited; no need for will-change.",[138,791,793],{"id":792},"faq","FAQ",[795,796,799,803],"details",{"className":797},[798],"faq-item",[800,801,802],"summary",{},"What does will-change do?",[14,804,805],{},"It hints that a property will change soon, allowing the browser to prepare, typically by promoting the element to its own compositing layer for transform and opacity changes.",[795,807,809,812],{"className":808},[798],[800,810,811],{},"How many layers are too many?",[14,813,814],{},"There is no fixed number; memory matters more than count. Dozens of small layers are usually fine; hundreds, or large layers on high-DPR phones, often cause problems.",[795,816,818,821],{"className":817},[798],[800,819,820],{},"Is translateZ(0) still needed?",[14,822,823,824,826],{},"Rarely. It was a hack to force layer promotion. Modern browsers promote animating elements automatically, and ",[29,825,42],{}," is the standard hint.",[795,828,830,833],{"className":829},[798],[800,831,832],{},"Why do elements get promoted without will-change?",[14,834,835],{},"Active transform or opacity animations, 3D transforms, video, canvas, fixed positioning in some cases, and overlap with other composited layers all cause promotion.",[795,837,839,842],{"className":838},[798],[800,840,841],{},"How do I see layer memory?",[14,843,844],{},"The Layers panel shows each layer's size and estimated memory, and the reason it was composited.",[795,846,848,851],{"className":847},[798],[800,849,850],{},"Does will-change: opacity also create a layer?",[14,852,853],{},"Yes, typically. Use it only for elements about to animate opacity.",[795,855,857,860],{"className":856},[798],[800,858,859],{},"Can layer explosion affect INP?",[14,861,862],{},"Indirectly. More layers mean more compositing and memory pressure, which slows frame production after interactions, especially on low-end devices.",[795,864,866,869],{"className":865},[798],[800,867,868],{},"Does removing will-change make animations stutter?",[14,870,871,872,874],{},"Usually not. Browsers promote elements automatically when a transform or opacity animation starts. If you do see a hitch on the first frame, add ",[29,873,42],{}," shortly before that one animation rather than permanently.",[795,876,878,881],{"className":877},[798],[800,879,880],{},"Are layers the reason my page uses so much memory?",[14,882,883],{},"They can be a large part of it on high-DPR phones. The Layers panel’s memory estimate shows how much; JavaScript heap and image decoding are the other common sources.",[795,885,887,890],{"className":886},[798],[800,888,889],{},"Do CSS frameworks add will-change?",[14,891,892,893,895],{},"Some component libraries add it to modals, drawers and carousels. Search the compiled CSS for ",[29,894,42],{}," and check whether the rules apply permanently or only during animation states.",[138,897,899],{"id":898},"related","Related",[143,901,902,909,915],{},[146,903,904,908],{},[18,905,907],{"href":906},"\u002Frendering-css-performance\u002Fanimation-and-compositing-performance\u002Fanimating-only-transform-and-opacity\u002F","Animating only transform and opacity"," — the animations layers are for.",[146,910,911,914],{},[18,912,913],{"href":20},"Animation & compositing performance"," — the topic overview.",[146,916,917,921],{},[18,918,920],{"href":919},"\u002Frendering-css-performance\u002Fcss-containment-and-content-visibility\u002Fisolating-widgets-with-css-contain\u002F","Isolating widgets with CSS contain"," — containment and stacking contexts.",[923,924,926],"script",{"type":925},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"will-change Overuse and Layer Explosion\",\n  \"description\": \"How compositing layers consume memory, how will-change and overlap create too many of them, and how to audit and fix layer explosion.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Audit and remove permanent promotion\",\n      \"text\": \"Remove will-change from elements that do not animate, and remove translateZ(0) hacks unless a specific rendering bug requires them (test after removal).\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Promote only shortly before and during animation\",\n      \"text\": \"Promote only shortly before and during animation\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Scope will-change in CSS to active states\",\n      \"text\": \"Scope will-change in CSS to active states\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Avoid overlap cascades\",\n      \"text\": \"Give promoted elements a high z-index or isolate them (isolation: isolate on a parent), so fewer elements need promotion to preserve order; check the Layers panel for \\\"overlaps\\\" reasons.\"\n    }\n  ]\n}\n",[923,928,929],{"type":925},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"will-change Overuse and Layer Explosion\",\n  \"description\": \"How compositing layers consume memory, how will-change and overlap create too many of them, and how to audit and fix layer explosion.\",\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\u002Frendering-css-performance\u002Fanimation-and-compositing-performance\u002Fwill-change-overuse-and-layer-explosion\u002F\"\n  }\n}\n",[923,931,932],{"type":925},"\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\": \"Rendering & CSS Performance\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Frendering-css-performance\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Animation & Compositing Performance\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Frendering-css-performance\u002Fanimation-and-compositing-performance\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"will-change Overuse and Layer Explosion\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Frendering-css-performance\u002Fanimation-and-compositing-performance\u002Fwill-change-overuse-and-layer-explosion\u002F\"\n    }\n  ]\n}\n",[934,935,936],"style",{},"html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}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":243,"searchDepth":282,"depth":282,"links":938},[939,940,941,947,948,949,950,951,952,953,954],{"id":140,"depth":282,"text":141},{"id":187,"depth":282,"text":188},{"id":217,"depth":282,"text":218,"children":942},[943,944,945,946],{"id":222,"depth":314,"text":223},{"id":235,"depth":314,"text":236},{"id":383,"depth":314,"text":384},{"id":436,"depth":314,"text":437},{"id":595,"depth":282,"text":596},{"id":606,"depth":282,"text":607},{"id":700,"depth":282,"text":701},{"id":710,"depth":282,"text":711},{"id":731,"depth":282,"text":732},{"id":764,"depth":282,"text":765},{"id":792,"depth":282,"text":793},{"id":898,"depth":282,"text":899},"How compositing layers consume memory, how will-change and overlap create too many of them, and how to audit and fix layer explosion.","md",{"slug":12,"type":958,"breadcrumb":959,"datePublished":967,"dateModified":967},"article",[960,963,964,965],{"name":961,"url":962},"Home","\u002F",{"name":26,"url":25},{"name":21,"url":20},{"name":5,"url":966},"\u002Frendering-css-performance\u002Fanimation-and-compositing-performance\u002Fwill-change-overuse-and-layer-explosion\u002F","2026-10-06",true,"\u002Frendering-css-performance\u002Fanimation-and-compositing-performance\u002Fwill-change-overuse-and-layer-explosion",{"title":971,"description":972},"will-change Overuse and Compositor Layer Explosion","Too many compositor layers waste GPU memory and slow frames. Audit layers in DevTools, remove blanket will-change, and promote elements only while they animate.","rendering-css-performance\u002Fanimation-and-compositing-performance\u002Fwill-change-overuse-and-layer-explosion\u002Findex","CjMCQjWfmtzy8lDrUf6sFSNM9d1gMyk0-_GRZWFfmbs",[976,980],{"title":977,"path":978,"stem":979,"children":-1},"View Transitions API Performance","\u002Frendering-css-performance\u002Fanimation-and-compositing-performance\u002Fview-transitions-api-performance","rendering-css-performance\u002Fanimation-and-compositing-performance\u002Fview-transitions-api-performance\u002Findex",{"title":981,"path":982,"stem":983,"children":-1},"Critical CSS & Render-Blocking Resources","\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources","rendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Findex",1791308077732]