How Do You Remove Unused CSS From a Site?

Source : CSS-Tricks

Here's what I'd like you to know upfront: this is a hard problem. If you've landed here because you're hoping to be pointed at a tool you can run that tells you exactly what CSS you can delete from your project, well... there are tools out there, but I'm warning you to be very careful with them because none of them can ever tell you the complete story.

I know what you want. You want to run the tool, delete what it tells you, and you have a faster site in 2.2 minutes. I'm sorry, but I'm going to disappoint you.

I think you should have a healthy level of skepticism for any tool like that. None of them are exactly lying to you — they often just don't have enough information to give you results that are safe and actionable. That's not to say you can't use them or it can't be done. Let's take a walk.

The motivation

I imagine the #1 driver for the desire to remove unused CSS is this:

You used a CSS framework (e.g. Bootstrap), included the framework's entire CSS file, and you only used a handful of the patterns it provides.

I can empathize with that. CSS frameworks often don't provide simple ways to opt-in to only what you are using, and customizing the source to work that way might require a level of expertise that your team doesn't have. That might even be the reason you reached for a framework to begin with.

Say you're loading 100 KB of CSS. I'd say that's a lot. (As I write, this site has ~23 KB, and there are quite a lot of pages and templates. I don't do anything special to reduce the size.) You have a suspicion, or some evidence, that you aren't using a portion of those bytes. I can see the cause for alarm. If you had a 100 KB JPG that you could compress to 20 KB by dropping it onto some tool, that's awesome and totally worth it. But the gain in doing that for CSS is even more important because CSS is loaded in the head and is render blocking.

Looking at "coverage"

Chrome's DevTools has a "Coverage" tab that will tell you how much of your CSS and JavaScript is in use. For example, if I visit the homepage of CSS-Tricks right now...

It tells me that 70.7% of my style.css file is unused. I imagine it's right, and that the rest of the CSS is used elsewhere. I didn't just dump a big style library onto this site; I wrote each line of that by hand, so I have my doubts that more than 2/3 of it is unused globally.

I hate to say it but I find looking at code coverage pretty useless. For me, it paints a dire picture of all this unused code on the site, which preys upon my doubts, but all I can do is worry about it.

This might be the very thing that's given you the idea that unused CSS needs to be discovered and deleted in the first place.

My primary concern

And you go, Perfect! I'll delete that CSS! And you do, only to find out it wasn't unused at all and you caused big styling problems throughout the site. Here's the thing: you don't actually know if a CSS selector is unused unless you:

  1. check coverage on every single page of your entire site...
  2. while executing all JavaScript...
  3. under every possible combination of state...
  4. in every possible combination of media queries you've used.

Checking your homepage doesn't count. Checking all your top-level pages doesn't count. You gotta dig through every page, including states that aren't always top-of-mind, not to mention all of the edge-case scenarios. Otherwise, you might end up deleting the dropdown styling for the credit card choice dropdown in the pop-up modal that appears for users with a disabled account who've logged in during their grace period that also have a gift card to apply.

This is too complex for automated tooling to promise their approach works perfectly, particularly when factoring in the unknowns of browser context (different screen sizes, different capabilities, different browsers) and third parties.

PurifyCSS Online takes some URLs and instantly provides a copy-pasteable chunk of CSS to use

It gave me the opportunity to put in other URLs (which is nice) but there are tens of thousands of URLs on CSS-Tricks. Many of them are fairly similar, but all of them have the potential of having selectors that are used. I get the impression it didn't execute JavaScript, because anything that came onto the page via JavaScript was left unstyled. It even deleted my :hover states.

Perhaps you can see why my trust in these tools is so low.

Part of a build process

This gives you a lot more opportunity for accuracy. That content blob could be a list of every single template, partial, and JavaScript file that builds your site. That might be a pain to maintain, but you'll certainly get more accuracy. It doesn't account for content in data stores (e.g. this blog post that lives in a database) and third-party JavaScript, but maybe that doesn't matter to you or you can account for it some other way.

So keep that in mind as well. It's dumb in the way it compares potential selector matches, which is both clever and dangerous.

UnusedCSS is an online service that crawls your site for you

Manually configuring a tool to look at every page on your site from every angle is certainly a chore and something that will need to be kept in sync day-to-day as your codebase evolves. Interestingly, the online service UnusedCSS tries to overcome this burden by crawling the site itself based on a single URL you give it.

I signed up for the paid service and pointed it at CSS-Tricks. I admit, with just a glance at the results, it feels a lot more accurate to me:

It also lets you download the cleaned file and offers lots of customization, like checking/unchecking selectors you actually want/don't want (e.g. you see a class name it doesn't think you need, but you know for sure you actually do need it) as well as prefixing and removing duplicate selectors.

I enjoyed the increased accuracy of the online crawling service, but there was a lot of noise, and I also can't see how I'd incorporate it practically into a day-to-day build and release process.

Tooling is generally used post-processing

Say your CSS is built with Less or Sass, then uses a postprocessor to compile it into CSS. You'd probably incorporate automated unused CSS cleaning at the very end of whatever other CSS preprocessing you do. Like...

  1. Sass
  2. PostCSS / Autoprefixer
  3. [ Clean Unsued CSS ]
  4. Production CSS

That both makes sense and is slightly funny to me. You don't actually fix the styling that generates unused CSS. Instead, you just wipe it away at the end of the build. I suppose JavaScript has been doing that kind of thing with tree shaking for a while, so there is a precedent, but it still feels weird to me because a CSS codebase is so directly hands-on. This setup almost encourages you to dump CSS wherever because there is no penalty for overdoing. It removes any incentive to understand how CSS is applied and used.

Visual regression testing

You screenshot as much of your site as possible — like all of the most important pages and those pages manipulated into different states — plus across different browsers and screen sizes. Those screenshots are created from your master branch on Git.

Then, before any branches gets merged into Master, you take all those screenshots of them and compare those to the screenshots in master. Not manually, but programmatically.

The relation to Atomic CSS and CSS-in-JS

I'm sure there are lots of people reading this that would say: I don't have unused CSS because the tooling I use generates the exact CSS it needs and nothing more.

Hey, that's kinda cool.

Maybe that's Atomizer. Maybe that's Tachyons that you also run through UnCSS and you are super careful about it. Maybe it's the Tailwind + PurgeCSS combo that's all the rage right now.

Maybe you tackle styles some other way. If you're tightly coupling JavaScript components and styles, like React and Emotion, or even just using CSS modules with whatever, less unused CSS is an advantage of CSS-in-JS. And because tree-shaking and code-splitting come along for the ride in many JavaScript-based build processes, you not only have less CSS but only load what you need at the moment.

How do you avoid unused CSS in future projects?

I think the future of styling is an intentional split between global and componentized styles. Most styles are scoped to components, but there are global styling choices that are made that take clear advantage of the cascade (e.g. global typography defaults).

If most styling is left scoped to components, I think there is less opportunity for unused styles to build up as it's much easier to wrap your mind around a small block of HTML and a small block of CSS that directly relate to each other. And when components die or evolve, the styling dies or evolves with it. CSS bundles are made from components that are actually used.

CSS-in-JS solutions naturally head in this direction as styles are bound to components. That's the main point, really. But it's not required. I like the generic approach of CSS modules, which is pretty much entirely for style scoping and doesn't mandate that you use some particular JavaScript framework.

If all that seems theoretical or out-of-reach, and you just have a Bootstrap site where you're trying to reduce the size of all that Bootstrap CSS, I'd recommend starting by using Bootstrap from the source instead of the final default distributed bundle. The source is SCSS and built from a bunch of high-level includes, so if you don't need particular parts of Bootstrap, you can remove them.

Pentechs've been excellent and a pleasure to work with.  Despite the complexity of the project they've delivered a superb result and kept all their promises.

CEO, Digiclips, UK

See what our clients say

Want to start a project?

Contact us at

+91 886 110 9173

+91 997 289 6003

+91 80 4200 7229