[{"data":1,"prerenderedAt":393},["ShallowReactive",2],{"\u002Farticles\u002Fhow-to-reduce-css-size-in-a-project":3,"i-ph:caret-right":389},{"id":4,"title":5,"body":6,"description":367,"draft":368,"extension":369,"head":370,"meta":371,"navigation":378,"ogImage":370,"path":379,"pubDate":380,"robots":370,"schemaOrg":370,"seo":381,"sitemap":383,"stem":384,"topics":385,"__hash__":388},"content\u002F articles\u002Fhow-to-reduce-css-size-in-a-project.md","How to Reduce CSS Size in a Project (Without Breaking UI)",{"type":7,"value":8,"toc":357},"minimark",[9,13,21,24,29,48,51,108,111,113,117,124,127,150,153,155,159,162,165,192,195,224,227,229,233,240,243,254,257,275,278,280,284,287,290,331,334,336,340],[10,11,12],"p",{},"Big CSS bundles rarely come from one dramatic mistake. They’re usually the sum of small choices: styling “just this one thing” with arbitrary values, adopting a UI library that ships a huge stylesheet, or accidentally making most CSS global so every route downloads everything.",[10,14,15,16,20],{},"The goal isn’t “no CSS.” The goal is ",[17,18,19],"strong",{},"ship only the CSS your users need for the routes they visit",", and do it in a way that doesn’t silently break production UI.",[22,23],"hr",{},[25,26,28],"h2",{"id":27},"avoid-tailwind-arbitrary-classes-they-add-noise-and-complicate-purging","Avoid Tailwind arbitrary classes (they add noise and complicate purging)",[10,30,31,32,35,36,40,41,40,44,47],{},"Tailwind stays small when your class names are ",[17,33,34],{},"static"," and reusable. Arbitrary values (",[37,38,39],"code",{},"bg-[#0f172a]",", ",[37,42,43],{},"w-[372px]",[37,45,46],{},"shadow-[...]",") tend to push you toward one-off styling and can force you to loosen purge rules when classes become dynamic.",[10,49,50],{},"What to do instead:",[52,53,54,70,101],"ul",{},[55,56,57,58,61,62,65,66,69],"li",{},"Prefer ",[17,59,60],{},"design tokens"," in ",[37,63,64],{},"tailwind.config"," (",[37,67,68],{},"theme.extend",") for colors, spacing, radii, shadows, font sizes.",[55,71,57,72,75,76],{},[17,73,74],{},"composed utilities"," for repeated patterns:\n",[52,77,78,81,94],{},[55,79,80],{},"shared static class strings (keep them literal, not generated)",[55,82,83,84,40,87,40,90,93],{},"small wrapper components (",[37,85,86],{},"\u003CButton>",[37,88,89],{},"\u003CCard>",[37,91,92],{},"\u003CBadge>",") that encode a consistent style",[55,95,96,97,100],{},"Tailwind layers like ",[37,98,99],{},"@layer components"," for semantic classes",[55,102,103,104,107],{},"If you must use an arbitrary value, keep it ",[17,105,106],{},"rare, static, and reviewed",".",[10,109,110],{},"A useful rule: if you see the same arbitrary value twice, it probably wants to be a token.",[22,112],{},[25,114,116],{"id":115},"avoid-ui-libraries-that-cant-tree-shake-or-purge-css-well","Avoid UI libraries that can’t tree-shake or purge CSS well",[10,118,119,120,123],{},"JavaScript tree-shaking is common. ",[17,121,122],{},"CSS tree-shaking is not guaranteed."," Many UI libraries ship a single big stylesheet (or inject global styles) that you can’t easily split by route or prune by usage.",[10,125,126],{},"Before you adopt a UI library, verify:",[52,128,129,136,143],{},[55,130,131,132,135],{},"It supports ",[17,133,134],{},"per-component imports"," (for both JS and CSS), or a build step that outputs “used-only” CSS.",[55,137,138,139,142],{},"It documents how to work with ",[17,140,141],{},"purge"," (Tailwind, PurgeCSS, or the framework’s native purge).",[55,144,145,146,149],{},"It doesn’t require a giant ",[17,147,148],{},"global CSS import"," just to render a few components.",[10,151,152],{},"If you can’t answer “how does this library ensure unused CSS isn’t shipped?”, you’ll usually pay for it in bundle size.",[22,154],{},[25,156,158],{"id":157},"use-a-css-purge-plugin-but-treat-it-like-a-risky-refactor","Use a CSS purge plugin, but treat it like a risky refactor",[10,160,161],{},"Purging is one of the highest-impact optimizations for CSS size—and one of the easiest ways to ship broken UI if your purge config misses a template source or dynamic class pattern.",[10,163,164],{},"Best practices:",[52,166,167,179,185],{},[55,168,169,170,173,174,178],{},"Run purge for ",[17,171,172],{},"production builds"," and ensure the tool scans ",[175,176,177],"em",{},"all"," rendered templates (pages, components, content, emails, CMS templates).",[55,180,57,181,184],{},[17,182,183],{},"static class strings"," over generated class names.",[55,186,187,188,191],{},"If you must safelist, do it ",[17,189,190],{},"narrowly"," (explicit list over broad regex).",[10,193,194],{},"How to validate you didn’t break anything:",[52,196,197,200],{},[55,198,199],{},"If you have screenshot tests, run them and review diffs for key routes.",[55,201,202,203],{},"If you don’t, do a manual pass that specifically checks:\n",[52,204,205,215,218,221],{},[55,206,207,208,40,211,214],{},"responsive variants (",[37,209,210],{},"sm:",[37,212,213],{},"md:","), hover\u002Ffocus\u002Factive states",[55,216,217],{},"dark mode variants",[55,219,220],{},"modals, toasts, dropdowns, empty states, error states",[55,222,223],{},"rarely visited routes (settings\u002Fadmin\u002Fonboarding)",[10,225,226],{},"Purging should reduce CSS. It shouldn’t reduce trust.",[22,228],{},[25,230,232],{"id":231},"watch-out-for-global-css-exports-they-prevent-page-level-splitting","Watch out for global CSS exports (they prevent page-level splitting)",[10,234,235,236,239],{},"One very common reason CSS stays large: your app ends up in a state where ",[17,237,238],{},"most styles are global",", so every route loads nearly everything.",[10,241,242],{},"This often happens when:",[52,244,245,248,251],{},[55,246,247],{},"a root entry imports a “main.css” that imports lots of component\u002Fpage CSS",[55,249,250],{},"a UI library requires a global stylesheet",[55,252,253],{},"framework limitations or dynamic routing patterns prevent clean CSS chunking",[10,255,256],{},"What to do:",[52,258,259,266,272],{},[55,260,261,262,265],{},"Keep global CSS ",[17,263,264],{},"minimal",": tokens (CSS variables), tiny reset, base typography—nothing route-specific.",[55,267,268,269,107],{},"Co-locate route-specific styling with the route\u002Fmodule so your bundler has a chance to ",[17,270,271],{},"split by page",[55,273,274],{},"Audit imports: if a stylesheet is imported by the root layout\u002Fapp entry, it’s effectively global.",[10,276,277],{},"If you want small CSS, global CSS should be a deliberate choice, not an accident.",[22,279],{},[25,281,283],{"id":282},"keep-best-practices-consistent-across-your-team-and-ai-agents","Keep best practices consistent across your team (and AI agents)",[10,285,286],{},"CSS bloat is often a process problem: different people (and agents) produce different styling patterns, which increases unique utilities, safelists, and global overrides.",[10,288,289],{},"Team conventions that keep CSS lean:",[52,291,292,300,314],{},[55,293,294,295],{},"Define a “styling decision tree”:\n",[52,296,297],{},[55,298,299],{},"utilities first → tokens second → components\u002Flayers for repetition → arbitrary values last",[55,301,302,303],{},"Add lightweight PR checks:\n",[52,304,305,308,311],{},[55,306,307],{},"flag new global CSS imports",[55,309,310],{},"flag broad purge safelists",[55,312,313],{},"track CSS output size (even just “before vs after” from build stats)",[55,315,316,317],{},"Teach your AI agents the same rules:\n",[52,318,319,322,325,328],{},[55,320,321],{},"default to tokens and reusable patterns",[55,323,324],{},"avoid arbitrary classes unless justified",[55,326,327],{},"never expand purge safelists casually",[55,329,330],{},"don’t introduce global CSS without a clear reason",[10,332,333],{},"If the rules aren’t shared, the CSS will grow back—quietly.",[22,335],{},[25,337,339],{"id":338},"quick-checklist","Quick checklist",[52,341,342,345,348,351,354],{},[55,343,344],{},"Reduce arbitrary Tailwind values; add tokens.",[55,346,347],{},"Choose UI libraries with proven CSS purging\u002Ftree-shaking.",[55,349,350],{},"Purge in production builds, scan all templates, safelist narrowly.",[55,352,353],{},"Keep global CSS minimal; avoid importing route styles globally.",[55,355,356],{},"Standardize conventions for humans and AI agents; enforce with PR checks.",{"title":358,"searchDepth":359,"depth":359,"links":360},"",2,[361,362,363,364,365,366],{"id":27,"depth":359,"text":28},{"id":115,"depth":359,"text":116},{"id":157,"depth":359,"text":158},{"id":231,"depth":359,"text":232},{"id":282,"depth":359,"text":283},{"id":338,"depth":359,"text":339},"Practical ways to shrink CSS bundles: Tailwind discipline, choosing tree-shakeable UI libs, safe purging, avoiding accidental global CSS, and setting team\u002FAI conventions.",false,"md",null,{"type":372,"authors":373,"tools":375},"article",[374],"dubem",[376,377],"tailwind","nuxtjs",true,"\u002Farticles\u002Fhow-to-reduce-css-size-in-a-project","2026-04-28 12:00:00",{"keywords":382,"title":5,"description":367},"css size, css bundle, tailwind purge, tailwind arbitrary classes, tree shaking, purgecss, nuxt css, performance",{"loc":379}," articles\u002Fhow-to-reduce-css-size-in-a-project",[386,387],"Frontend","Performance","IZB19tSXFSnpk6d4JCZLBJMTXq857SSgo-hj67XxaYQ",{"left":390,"top":390,"width":391,"height":391,"rotate":390,"vFlip":368,"hFlip":368,"body":392},0,256,"\u003Cpath fill=\"currentColor\" d=\"m181.66 133.66l-80 80a8 8 0 0 1-11.32-11.32L164.69 128L90.34 53.66a8 8 0 0 1 11.32-11.32l80 80a8 8 0 0 1 0 11.32\"\u002F>",1783514974241]