[{"data":1,"prerenderedAt":1014},["ShallowReactive",2],{"content:\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fremoving-unused-css-with-purgecss":3,"surroundings:\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fremoving-unused-css-with-purgecss":1005},{"id":4,"title":5,"body":6,"description":985,"extension":986,"meta":987,"navigation":998,"path":999,"seo":1000,"stem":1003,"__hash__":1004},"content\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fremoving-unused-css-with-purgecss\u002Findex.md","Removing Unused CSS with PurgeCSS",{"type":7,"value":8,"toc":967},"minimark",[9,14,29,32,121,126,160,164,170,176,182,188,192,197,457,461,471,475,478,482,485,599,603,606,610,623,745,749,752,756,774,777,781,807,811,821,834,840,846,850,862,871,880,889,898,907,916,925,929,952,957,960,963],[10,11,13],"h1",{"id":12},"how-to-remove-unused-css-with-purgecss","How to Remove Unused CSS with PurgeCSS",[15,16,17,18,23,24,28],"p",{},"This guide is part of ",[19,20,22],"a",{"href":21},"\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002F","Critical CSS & Render-Blocking Resources",", within ",[19,25,27],{"href":26},"\u002Frendering-css-performance\u002F","Rendering & CSS Performance",". CSS frameworks such as Bootstrap and Bulma, component libraries and years of accumulated site styles commonly result in stylesheets where most rules are never used on any page. The DevTools Coverage tab often shows 70–90% of CSS bytes unused on a given page. Unused CSS still has to be downloaded, parsed and kept in memory, and when it is render-blocking it directly delays first paint.",[15,30,31],{},"PurgeCSS scans your templates, components and scripts for class names, IDs and element selectors, and removes CSS rules that do not match any of them. It is effective and simple, but it is a static analysis: classes built dynamically in JavaScript, added by third-party scripts or coming from a CMS can be removed by mistake. Safe use depends on configuring the content sources correctly and safelisting anything dynamic.",[15,33,34],{},[35,36,42,43,42,50,42,54,42,57,42,66,42,72,42,79,42,87,42,92,42,96,42,103,42,107,42,111,42,117,42],"svg",{"viewBox":37,"width":38,"role":39,"ariaLabel":40,"style":41},"0 0 760 163","100%","img","Bar chart comparing compressed CSS size for a framework-based site before and after PurgeCSS.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[44,45],"rect",{"className":46,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],"svg-canvas","0","#ffffff",[51,52,53],"title",{},"Stylesheet size before and after purging (compressed)",[55,56,40],"desc",{},[44,58],{"x":59,"y":59,"width":60,"height":61,"rx":62,"fill":63,"stroke":64,"style":65},"1","758","161","10","none","currentColor","stroke-opacity:0.18",[67,68,53],"text",{"x":69,"y":70,"fill":64,"style":71},"28.0","34.0","font-size:16px;font-weight:700",[67,73,78],{"x":74,"y":75,"fill":64,"style":76,"textAnchor":77},"161.6","70.0","font-size:13px","end","Bootstrap + site CSS",[44,80],{"x":81,"y":82,"width":83,"height":84,"rx":85,"fill":63,"stroke":64,"style":86},"173.6","56.0","494.4","19","3","fill-opacity:0.7;stroke-opacity:0.35",[67,88,91],{"x":89,"y":75,"fill":64,"style":90},"674.0","font-size:12px;font-weight:600","38KB",[67,93,95],{"x":74,"y":94,"fill":64,"style":76,"textAnchor":77},"101.0","After PurgeCSS",[44,97],{"x":81,"y":98,"width":99,"height":84,"rx":85,"fill":100,"stroke":101,"style":102},"87.0","117.1","#ffc300","#b8860b","fill-opacity:0.7;stroke-opacity:0.9",[67,104,106],{"x":105,"y":94,"fill":64,"style":90},"296.7","9KB",[67,108,110],{"x":74,"y":109,"fill":64,"style":76,"textAnchor":77},"132.0","Critical subset (inlined)",[44,112],{"x":81,"y":113,"width":114,"height":84,"rx":85,"fill":115,"stroke":115,"style":116},"118.0","65.1","#0466c8","fill-opacity:0.55;stroke-opacity:0.9",[67,118,120],{"x":119,"y":109,"fill":64,"style":90},"244.7","5KB",[122,123,125],"h2",{"id":124},"rapid-diagnosis","Rapid Diagnosis",[127,128,129,137,143,154],"ul",{},[130,131,132,136],"li",{},[133,134,135],"strong",{},"Use the Coverage tab"," (DevTools → More tools → Coverage) on key templates to estimate unused bytes.",[130,138,139,142],{},[133,140,141],{},"Identify the sources"," of CSS: framework, component library, site styles, third-party widgets.",[130,144,145,148,149,153],{},[133,146,147],{},"Find dynamic class usage",": string concatenation (",[150,151,152],"code",{},"'btn-' + variant","), state classes added by JS, CMS-authored HTML.",[130,155,156,159],{},[133,157,158],{},"Check for existing purging",": utility frameworks like Tailwind already purge via their content configuration.",[122,161,163],{"id":162},"root-cause-analysis","Root Cause Analysis",[15,165,166,169],{},[133,167,168],{},"1. Frameworks ship everything."," You use a grid and buttons; you receive carousels, modals and dozens of components.",[15,171,172,175],{},[133,173,174],{},"2. Accumulated styles."," Removed features leave their CSS behind.",[15,177,178,181],{},[133,179,180],{},"3. One global stylesheet."," Every page loads every other page's styles.",[15,183,184,187],{},[133,185,186],{},"4. Fear of breaking things."," Without tooling, nobody dares delete old CSS.",[122,189,191],{"id":190},"step-by-step-resolution","Step-by-Step Resolution",[193,194,196],"h3",{"id":195},"_1-configure-purgecss-with-all-content-sources","1. Configure PurgeCSS with all content sources",[198,199,204],"pre",{"className":200,"code":201,"language":202,"meta":203,"style":203},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F postcss.config.cjs\nmodule.exports = {\n  plugins: [\n    require('@fullhuman\u002Fpostcss-purgecss')({\n      content: ['.\u002Fsrc\u002F**\u002F*.{html,vue,jsx,tsx,js,ts,md}', '.\u002Fcontent\u002F**\u002F*.md'],\n      defaultExtractor: (content) => content.match(\u002F[\\w-\u002F:]+(?\u003C!:)\u002Fg) || [],\n      safelist: {\n        standard: [\u002F^is-\u002F, \u002F^has-\u002F, 'show', 'collapsing', 'fade'],   \u002F\u002F JS-added state classes\n        deep: [\u002F^cms-\u002F],                                             \u002F\u002F CMS rich text containers\n        greedy: [\u002Ftooltip\u002F, \u002Fmodal\u002F],\n      },\n    }),\n  ],\n};\n\u002F\u002F trade-off: broad safelists keep more CSS but reduce breakage risk; start broad\n\u002F\u002F and tighten once visual tests cover the affected components.\n","javascript","",[150,205,206,215,236,242,259,277,334,340,386,405,421,427,433,439,445,451],{"__ignoreMap":203},[207,208,211],"span",{"class":209,"line":210},"line",1,[207,212,214],{"class":213},"sjfSM","\u002F\u002F postcss.config.cjs\n",[207,216,218,222,226,229,233],{"class":209,"line":217},2,[207,219,221],{"class":220},"sPXB4","module",[207,223,225],{"class":224},"saISM",".",[207,227,228],{"class":220},"exports",[207,230,232],{"class":231},"sPARh"," =",[207,234,235],{"class":224}," {\n",[207,237,239],{"class":209,"line":238},3,[207,240,241],{"class":224},"  plugins: [\n",[207,243,245,249,252,256],{"class":209,"line":244},4,[207,246,248],{"class":247},"smZ65","    require",[207,250,251],{"class":224},"(",[207,253,255],{"class":254},"sZ8jY","'@fullhuman\u002Fpostcss-purgecss'",[207,257,258],{"class":224},")({\n",[207,260,262,265,268,271,274],{"class":209,"line":261},5,[207,263,264],{"class":224},"      content: [",[207,266,267],{"class":254},"'.\u002Fsrc\u002F**\u002F*.{html,vue,jsx,tsx,js,ts,md}'",[207,269,270],{"class":224},", ",[207,272,273],{"class":254},"'.\u002Fcontent\u002F**\u002F*.md'",[207,275,276],{"class":224},"],\n",[207,278,280,283,286,290,293,296,299,302,304,307,310,314,317,320,323,326,328,331],{"class":209,"line":279},6,[207,281,282],{"class":247},"      defaultExtractor",[207,284,285],{"class":224},": (",[207,287,289],{"class":288},"sQw3B","content",[207,291,292],{"class":224},") ",[207,294,295],{"class":231},"=>",[207,297,298],{"class":224}," content.",[207,300,301],{"class":247},"match",[207,303,251],{"class":224},[207,305,306],{"class":254},"\u002F",[207,308,309],{"class":220},"[",[207,311,313],{"class":312},"sn2CQ","\\w",[207,315,316],{"class":220},"-\u002F:]",[207,318,319],{"class":231},"+",[207,321,322],{"class":254},"(?\u003C!:)\u002F",[207,324,325],{"class":231},"g",[207,327,292],{"class":224},[207,329,330],{"class":231},"||",[207,332,333],{"class":224}," [],\n",[207,335,337],{"class":209,"line":336},7,[207,338,339],{"class":224},"      safelist: {\n",[207,341,343,346,348,351,354,357,360,362,365,367,370,372,375,377,380,383],{"class":209,"line":342},8,[207,344,345],{"class":224},"        standard: [",[207,347,306],{"class":254},[207,349,350],{"class":231},"^",[207,352,353],{"class":254},"is-\u002F",[207,355,356],{"class":224},",",[207,358,359],{"class":254}," \u002F",[207,361,350],{"class":231},[207,363,364],{"class":254},"has-\u002F",[207,366,270],{"class":224},[207,368,369],{"class":254},"'show'",[207,371,270],{"class":224},[207,373,374],{"class":254},"'collapsing'",[207,376,270],{"class":224},[207,378,379],{"class":254},"'fade'",[207,381,382],{"class":224},"],   ",[207,384,385],{"class":213},"\u002F\u002F JS-added state classes\n",[207,387,389,392,394,396,399,402],{"class":209,"line":388},9,[207,390,391],{"class":224},"        deep: [",[207,393,306],{"class":254},[207,395,350],{"class":231},[207,397,398],{"class":254},"cms-\u002F",[207,400,401],{"class":224},"],                                             ",[207,403,404],{"class":213},"\u002F\u002F CMS rich text containers\n",[207,406,408,411,414,416,419],{"class":209,"line":407},10,[207,409,410],{"class":224},"        greedy: [",[207,412,413],{"class":254},"\u002Ftooltip\u002F",[207,415,356],{"class":224},[207,417,418],{"class":254}," \u002Fmodal\u002F",[207,420,276],{"class":224},[207,422,424],{"class":209,"line":423},11,[207,425,426],{"class":224},"      },\n",[207,428,430],{"class":209,"line":429},12,[207,431,432],{"class":224},"    }),\n",[207,434,436],{"class":209,"line":435},13,[207,437,438],{"class":224},"  ],\n",[207,440,442],{"class":209,"line":441},14,[207,443,444],{"class":224},"};\n",[207,446,448],{"class":209,"line":447},15,[207,449,450],{"class":213},"\u002F\u002F trade-off: broad safelists keep more CSS but reduce breakage risk; start broad\n",[207,452,454],{"class":209,"line":453},16,[207,455,456],{"class":213},"\u002F\u002F and tighten once visual tests cover the affected components.\n",[193,458,460],{"id":459},"_2-avoid-dynamic-class-construction","2. Avoid dynamic class construction",[15,462,463,464,466,467,470],{},"Replace ",[150,465,152],{}," with full class names in a lookup (",[150,468,469],{},"{ primary: 'btn-primary', danger: 'btn-danger' }","), so the extractor can see them.",[193,472,474],{"id":473},"_3-run-visual-regression-tests","3. Run visual regression tests",[15,476,477],{},"Screenshot key templates and states (open menus, modals, form errors) before and after purging, and compare. Interaction states are where purging most often breaks things.",[193,479,481],{"id":480},"_4-split-css-per-route-if-pages-differ-greatly","4. Split CSS per route if pages differ greatly",[15,483,484],{},"Bundlers with CSS code splitting (Vite, webpack with mini-css-extract) produce per-route CSS, which reduces unused CSS further without purging.",[15,486,487],{},[35,488,42,491,42,494,42,497,42,499,42,502,42,504,42,511,42,518,42,523,42,526,42,530,42,534,42,537,42,541,42,545,42,548,42,552,42,556,42,563,42,567,42,571,42,576,42,579,42,582,42,586,42,589,42,592,42,595,42],{"viewBox":489,"width":38,"role":39,"ariaLabel":490,"style":41},"0 0 760 318","Steps that make removing unused CSS safe for production.",[44,492],{"className":493,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],[51,495,496],{},"Safe purging checklist",[55,498,490],{},[44,500],{"x":59,"y":59,"width":60,"height":501,"rx":62,"fill":63,"stroke":64,"style":65},"316",[67,503,496],{"x":69,"y":70,"fill":64,"style":71},[44,505],{"x":506,"y":82,"width":507,"height":508,"rx":509,"fill":115,"stroke":115,"style":510},"72.0","660.0","51.0","6","fill-opacity:0.14;stroke-opacity:0.9",[67,512,517],{"x":513,"y":514,"fill":64,"style":515,"textAnchor":516},"86.0","77.0","font-size:13px;font-weight:700","start","List every content source",[67,519,522],{"x":513,"y":520,"fill":64,"style":521,"textAnchor":516},"94.0","font-size:12px","templates, components, Markdown, CMS HTML",[44,524],{"x":506,"y":525,"width":507,"height":508,"rx":509,"fill":115,"stroke":115,"style":510},"119.0",[67,527,529],{"x":513,"y":528,"fill":64,"style":515,"textAnchor":516},"140.0","Safelist JS-added classes",[67,531,533],{"x":513,"y":532,"fill":64,"style":521,"textAnchor":516},"157.0","states, plugins, third-party widgets",[44,535],{"x":506,"y":536,"width":507,"height":508,"rx":509,"fill":115,"stroke":115,"style":510},"182.0",[67,538,540],{"x":513,"y":539,"fill":64,"style":515,"textAnchor":516},"203.0","Remove dynamic class concatenation",[67,542,544],{"x":513,"y":543,"fill":64,"style":521,"textAnchor":516},"220.0","use full class names in lookups",[44,546],{"x":506,"y":547,"width":507,"height":508,"rx":509,"fill":115,"stroke":115,"style":510},"245.0",[67,549,551],{"x":513,"y":550,"fill":64,"style":515,"textAnchor":516},"266.0","Visual regression on states",[67,553,555],{"x":513,"y":554,"fill":64,"style":521,"textAnchor":516},"283.0","menus, modals, errors, empty states",[209,557],{"x1":558,"y1":559,"x2":558,"y2":560,"stroke":64,"strokeWidth":561,"style":562},"43.0","95.5","130.5","1.5","stroke-opacity:0.3",[209,564],{"x1":558,"y1":565,"x2":558,"y2":566,"stroke":64,"strokeWidth":561,"style":562},"158.5","193.5",[209,568],{"x1":558,"y1":569,"x2":558,"y2":570,"stroke":64,"strokeWidth":561,"style":562},"221.5","256.5",[572,573],"circle",{"cx":558,"cy":574,"r":575,"fill":115},"81.5","13",[67,577,59],{"x":558,"y":513,"fill":49,"style":515,"textAnchor":578},"middle",[572,580],{"cx":558,"cy":581,"r":575,"fill":115},"144.5",[67,583,585],{"x":558,"y":584,"fill":49,"style":515,"textAnchor":578},"149.0","2",[572,587],{"cx":558,"cy":588,"r":575,"fill":115},"207.5",[67,590,85],{"x":558,"y":591,"fill":49,"style":515,"textAnchor":578},"212.0",[572,593],{"cx":558,"cy":594,"r":575,"fill":115},"270.5",[67,596,598],{"x":558,"y":597,"fill":49,"style":515,"textAnchor":578},"275.0","4",[122,600,602],{"id":601},"verification","Verification",[15,604,605],{},"Compare CSS size before and after (compressed). Run visual regression tests across templates and interaction states. Check the Coverage tab again: unused share should drop sharply. In the lab, FCP and style recalculation time should improve slightly; in the field, watch for error reports or support tickets about broken layouts in the days after release.",[122,607,609],{"id":608},"worked-example-a-saas-marketing-site","Worked Example: A SaaS Marketing Site",[15,611,612,613,270,616,270,619,622],{},"A SaaS company's marketing site used Bootstrap plus 60KB of custom styles, totalling 41KB compressed and render-blocking on every page. Coverage showed 84% unused on the homepage. PurgeCSS with content globs for templates and Markdown, plus a safelist for Bootstrap's JavaScript-driven classes (",[150,614,615],{},"show",[150,617,618],{},"collapsing",[150,620,621],{},"modal-*","), reduced the stylesheet to 10KB compressed. Visual regression found two problems — a pricing toggle that built classes dynamically and a third-party chat widget relying on site classes — both fixed with full class names and a safelist entry. Mobile FCP p75 improved by 320ms.",[15,624,625],{},[35,626,42,629,42,632,42,635,42,637,42,654,42,657,42,659,42,663,42,668,42,672,42,676,42,679,42,683,42,686,42,690,42,694,42,697,42,700,42,703,42,707,42,710,42,713,42,716,42,720,42,723,42,726,42,733,42,737,42,741,42],{"viewBox":627,"width":38,"role":39,"ariaLabel":628,"style":41},"0 0 760 149","Steps from measuring coverage through configuring PurgeCSS to visual verification and release.",[44,630],{"className":631,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],[51,633,634],{},"Purging workflow",[55,636,628],{},[638,639,640],"defs",{},[641,642,649],"marker",{"id":643,"viewBox":644,"refX":645,"refY":646,"markerWidth":647,"markerHeight":647,"orient":648},"fa4d7e98a3","0 0 10 10","9","5","7","auto-start-reverse",[650,651],"path",{"d":652,"fill":64,"style":653},"M0 0 L10 5 L0 10 z","fill-opacity:0.7",[44,655],{"x":59,"y":59,"width":60,"height":656,"rx":62,"fill":63,"stroke":64,"style":65},"147",[67,658,634],{"x":69,"y":70,"fill":64,"style":71},[44,660],{"x":69,"y":82,"width":661,"height":662,"rx":509,"fill":115,"stroke":115,"style":510},"108.8","71.0",[67,664,667],{"x":665,"y":666,"fill":64,"style":515,"textAnchor":578},"82.4","78.0","Coverage",[67,669,671],{"x":665,"y":670,"fill":64,"style":521,"textAnchor":578},"96.0","measure unused",[67,673,675],{"x":665,"y":674,"fill":64,"style":521,"textAnchor":578},"112.0","share",[44,677],{"x":678,"y":82,"width":661,"height":662,"rx":509,"fill":115,"stroke":115,"style":510},"176.8",[67,680,682],{"x":681,"y":666,"fill":64,"style":515,"textAnchor":578},"231.2","Configure",[67,684,685],{"x":681,"y":670,"fill":64,"style":521,"textAnchor":578},"content globs",[44,687],{"x":688,"y":82,"width":661,"height":662,"rx":509,"fill":100,"stroke":101,"style":689},"325.6","fill-opacity:0.24;stroke-opacity:0.9",[67,691,693],{"x":692,"y":666,"fill":64,"style":515,"textAnchor":578},"380.0","Safelist",[67,695,696],{"x":692,"y":670,"fill":64,"style":521,"textAnchor":578},"dynamic + JS",[67,698,699],{"x":692,"y":674,"fill":64,"style":521,"textAnchor":578},"classes",[44,701],{"x":702,"y":82,"width":661,"height":662,"rx":509,"fill":115,"stroke":115,"style":510},"474.4",[67,704,706],{"x":705,"y":666,"fill":64,"style":515,"textAnchor":578},"528.8","Visual tests",[67,708,709],{"x":705,"y":670,"fill":64,"style":521,"textAnchor":578},"templates +",[67,711,712],{"x":705,"y":674,"fill":64,"style":521,"textAnchor":578},"states",[44,714],{"x":715,"y":82,"width":661,"height":662,"rx":509,"fill":115,"stroke":115,"style":510},"623.2",[67,717,719],{"x":718,"y":666,"fill":64,"style":515,"textAnchor":578},"677.6","Release",[67,721,722],{"x":718,"y":670,"fill":64,"style":521,"textAnchor":578},"watch error",[67,724,725],{"x":718,"y":674,"fill":64,"style":521,"textAnchor":578},"reports",[209,727],{"x1":728,"y1":729,"x2":730,"y2":729,"stroke":64,"strokeWidth":561,"style":731,"markerEnd":732},"136.8","91.5","174.8","stroke-opacity:0.6","url(#fa4d7e98a3)",[209,734],{"x1":735,"y1":729,"x2":736,"y2":729,"stroke":64,"strokeWidth":561,"style":731,"markerEnd":732},"285.6","323.6",[209,738],{"x1":739,"y1":729,"x2":740,"y2":729,"stroke":64,"strokeWidth":561,"style":731,"markerEnd":732},"434.4","472.4",[209,742],{"x1":743,"y1":729,"x2":744,"y2":729,"stroke":64,"strokeWidth":561,"style":731,"markerEnd":732},"583.2","621.2",[122,746,748],{"id":747},"beyond-purgecss","Beyond PurgeCSS",[15,750,751],{},"Purging is a clean-up for CSS architectures that ship everything. Longer term, approaches that only generate what is used avoid the problem: utility-first frameworks with content scanning (Tailwind), component-scoped CSS that is code-split with the components (CSS modules, Vue SFC styles, Svelte), and zero-runtime CSS-in-JS. For legacy global stylesheets, periodically run coverage across a crawl of all templates to find rules unused anywhere, then delete them from source rather than purging at build time.",[122,753,755],{"id":754},"finding-dynamic-classes-before-they-break","Finding Dynamic Classes Before They Break",[15,757,758,759,270,762,765,766,769,770,773],{},"The most reliable way to build a safelist is to search the codebase for the patterns that hide class names from static analysis. Look for template literals and concatenation that produce class strings (",[150,760,761],{},"`col-${n}`",[150,763,764],{},"'is-' + state","), ",[150,767,768],{},"classList.add"," and ",[150,771,772],{},"classList.toggle"," calls with variables, framework class bindings with computed values, and any HTML that arrives from a CMS, a Markdown renderer or an API. Third-party scripts that inject markup — chat widgets, cookie banners, embedded forms — are another source; inspect the DOM they create and safelist their prefixes.",[15,775,776],{},"A practical approach is to run PurgeCSS in report-only mode first: generate the purged CSS, diff the removed selectors against the original, and scan the removed list by eye. Selectors you recognise as interaction states, plugin classes or CMS styles go into the safelist before the first production release.",[122,778,780],{"id":779},"common-mistakes","Common Mistakes",[127,782,783,789,795,801],{},[130,784,785,788],{},[133,786,787],{},"Missing content sources."," CMS HTML or Markdown not scanned; their classes are purged.",[130,790,791,794],{},[133,792,793],{},"Dynamic class names."," String concatenation hides classes from the extractor.",[130,796,797,800],{},[133,798,799],{},"No visual tests."," Breakage in menus or error states goes unnoticed.",[130,802,803,806],{},[133,804,805],{},"Purging third-party widget CSS."," Widgets that inject HTML at runtime need safelists.",[122,808,810],{"id":809},"edge-cases","Edge Cases",[15,812,813,816,817,820],{},[133,814,815],{},"Attribute selectors."," Selectors such as ",[150,818,819],{},"[data-state=\"open\"]"," need the attribute values in content or safelists.",[15,822,823,826,827,270,830,833],{},[133,824,825],{},"Pseudo-classes and elements."," PurgeCSS keeps rules if the base selector matches; ",[150,828,829],{},":hover",[150,831,832],{},"::before"," are not a problem.",[15,835,836,839],{},[133,837,838],{},"Keyframes and font-face."," Enable options to remove unused keyframes and font faces, but verify animations still work.",[15,841,842,845],{},[133,843,844],{},"CSS-in-JS."," Runtime styles are not affected by PurgeCSS; it only processes static CSS files.",[122,847,849],{"id":848},"faq","FAQ",[851,852,855,859],"details",{"className":853},[854],"faq-item",[856,857,858],"summary",{},"Is PurgeCSS safe for production?",[15,860,861],{},"Yes, when content sources and safelists are complete and visual regression tests cover interactive states. Most breakage comes from dynamic classes.",[851,863,865,868],{"className":864},[854],[856,866,867],{},"Does Tailwind need PurgeCSS?",[15,869,870],{},"No. Tailwind generates only the classes it finds in configured content files. The same rules apply: avoid dynamic class construction.",[851,872,874,877],{"className":873},[854],[856,875,876],{},"How much does unused CSS cost?",[15,878,879],{},"Download time when render-blocking, parse time, and memory. Large unused stylesheets also increase style recalculation work slightly, since more rules are considered.",[851,881,883,886],{"className":882},[854],[856,884,885],{},"Should I purge per page or site-wide?",[15,887,888],{},"Site-wide purging is simpler and keeps one cacheable stylesheet. Per-route CSS from code splitting is more precise but produces more files.",[851,890,892,895],{"className":891},[854],[856,893,894],{},"Can Lighthouse tell me which rules are unused?",[15,896,897],{},"Lighthouse reports unused CSS bytes per stylesheet; the Coverage tab shows the specific unused ranges for the current page.",[851,899,901,904],{"className":900},[854],[856,902,903],{},"What about unused CSS on other pages?",[15,905,906],{},"Coverage is per page. A rule unused on the homepage may be needed elsewhere, which is why PurgeCSS scans all templates instead of a single page.",[851,908,910,913],{"className":909},[854],[856,911,912],{},"How do I purge CSS in a Vite or Nuxt project?",[15,914,915],{},"Add the PurgeCSS PostCSS plugin to the PostCSS configuration the framework uses, point its content globs at your components, pages and content files, and build. Check the generated CSS size in the build output and run visual tests before deploying.",[851,917,919,922],{"className":918},[854],[856,920,921],{},"Can I remove unused CSS from a WordPress or CMS theme?",[15,923,924],{},"Yes, but CMS themes generate markup from many plugins and editors, so the content sources are harder to enumerate. Crawl a representative set of rendered pages, use their HTML as PurgeCSS content, and keep a generous safelist for plugin and block-editor classes. Re-run the crawl whenever plugins change.",[122,926,928],{"id":927},"related","Related",[127,930,931,938,945],{},[130,932,933,937],{},[19,934,936],{"href":935},"\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fextracting-critical-css-at-build-time\u002F","Extracting critical CSS at build time"," — inline the subset that matters most.",[130,939,940,944],{},[19,941,943],{"href":942},"\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fruntime-css-in-js-performance-cost\u002F","Runtime CSS-in-JS performance cost"," — the other source of CSS overhead.",[130,946,947,951],{},[19,948,950],{"href":949},"\u002Fjavascript-bundle-optimization-code-splitting\u002F","JavaScript bundle optimization"," — the same coverage technique for scripts.",[953,954,956],"script",{"type":955},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Remove Unused CSS with PurgeCSS\",\n  \"description\": \"How to remove unused CSS safely with PurgeCSS and similar tools, including safelisting dynamic classes and verifying templates visually.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Configure PurgeCSS with all content sources\",\n      \"text\": \"Configure PurgeCSS with all content sources\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Avoid dynamic class construction\",\n      \"text\": \"Replace 'btn-' + variant with full class names in a lookup ({ primary: 'btn-primary', danger: 'btn-danger' }), so the extractor can see them.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Run visual regression tests\",\n      \"text\": \"Screenshot key templates and states (open menus, modals, form errors) before and after purging, and compare.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Split CSS per route if pages differ greatly\",\n      \"text\": \"Bundlers with CSS code splitting (Vite, webpack with mini-css-extract) produce per-route CSS, which reduces unused CSS further without purging.\"\n    }\n  ]\n}\n",[953,958,959],{"type":955},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Remove Unused CSS with PurgeCSS\",\n  \"description\": \"How to remove unused CSS safely with PurgeCSS and similar tools, including safelisting dynamic classes and verifying templates visually.\",\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\u002Fcritical-css-and-render-blocking-resources\u002Fremoving-unused-css-with-purgecss\u002F\"\n  }\n}\n",[953,961,962],{"type":955},"\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\": \"Critical CSS & Render-Blocking Resources\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Removing Unused CSS with PurgeCSS\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fremoving-unused-css-with-purgecss\u002F\"\n    }\n  ]\n}\n",[964,965,966],"style",{},"html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}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 .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 .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html pre.shiki code .sn2CQ, html code.shiki .sn2CQ{--shiki-default:#024C1A;--shiki-default-font-weight:bold;--shiki-dark:#72F088;--shiki-dark-font-weight:bold;--shiki-light:#024C1A;--shiki-light-font-weight:bold}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":203,"searchDepth":217,"depth":217,"links":968},[969,970,971,977,978,979,980,981,982,983,984],{"id":124,"depth":217,"text":125},{"id":162,"depth":217,"text":163},{"id":190,"depth":217,"text":191,"children":972},[973,974,975,976],{"id":195,"depth":238,"text":196},{"id":459,"depth":238,"text":460},{"id":473,"depth":238,"text":474},{"id":480,"depth":238,"text":481},{"id":601,"depth":217,"text":602},{"id":608,"depth":217,"text":609},{"id":747,"depth":217,"text":748},{"id":754,"depth":217,"text":755},{"id":779,"depth":217,"text":780},{"id":809,"depth":217,"text":810},{"id":848,"depth":217,"text":849},{"id":927,"depth":217,"text":928},"How to remove unused CSS safely with PurgeCSS and similar tools, including safelisting dynamic classes and verifying templates visually.","md",{"slug":988,"type":989,"breadcrumb":990,"datePublished":997,"dateModified":997},"removing-unused-css-with-purgecss","article",[991,993,994,995],{"name":992,"url":306},"Home",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":996},"\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fremoving-unused-css-with-purgecss\u002F","2026-10-06",true,"\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fremoving-unused-css-with-purgecss",{"title":1001,"description":1002},"Removing Unused CSS with PurgeCSS Safely","Cut framework CSS by 70-90% with PurgeCSS: configure content globs, safelist dynamic classes, handle JS-added states, and verify nothing breaks visually.","rendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fremoving-unused-css-with-purgecss\u002Findex","gDYU0wGF1l2KW0VZ-5Z-U8M-764SYzRkuqCOfkOqrzA",[1006,1010],{"title":1007,"path":1008,"stem":1009},"Loading Non-Critical CSS Asynchronously","\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Floading-non-critical-css-asynchronously","rendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Floading-non-critical-css-asynchronously\u002Findex",{"title":1011,"path":1012,"stem":1013},"Runtime CSS-in-JS Performance Cost","\u002Frendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fruntime-css-in-js-performance-cost","rendering-css-performance\u002Fcritical-css-and-render-blocking-resources\u002Fruntime-css-in-js-performance-cost\u002Findex",1791308079946]