UnCSS: Remove unused styles from CSS
github.com
github.com
It's such a hard problem to solve and the Stylesheet Snowball is one of the most frustrating pieces of technical debt a large site can pick up.
It makes me wonder if scoped CSS modules, despite fundamentally breaking CSS with their hyper specific hybrid BEM-class-ids might be the best preemptive solution even when you're not scaling up to massive SPAs.
Edit. Meant CSS modules, wrote CSS components. I am not a clever man.
I came back to that project 7mths later and I could find everything exactly where I left it, I realised that past me had made a reasonable choice for the future.
Now I hold my nose and use it (or something like it) everywhere.
Even b-<somefoo> { <otherstuff> } helps hugely, I just wish there was an easier way of stopping accidental stomping from other selectors outside b-<somefoo>.
How is that silly? Assume e.g. a very simply dynamic list, where you just want highlight rows after clicking on them. Should it set the CSS properties of the <tr> directly? It makes more sense to dynamically add/remove a CSS class such as "selected-row". However, since initially no row is selected that class does not appear in the initial HTML.
> scoped CSS components
Not sure if this is the same, but I had very good experience with component-oriented frameworks where each component has an HTML snippet and CSS snippet attached to it. The CSS is written in a way that it affects only the responsibility scope of the component, nothing outside the component, nothing inside child components.[1] Then, these CSS snippets are simply collected into a large (and perhaps compressed) CSS file.
[1] This is usually done be either prefixing all CSS rules with a component-specific class name, or by using a component-specific custom HTML element and selecting on that. Stepping into children is avoided by using only child selectors ("a > b > * > * > c" instead of "a b c"), so the rules don't reach deeply except for the cascading properties of CSS itself.
I got as far as starting to build us a tool to traverse our raw jsx to identify these programmatically generated classes, but my implementation was a bit flakey for various reasons and required too much config to make it worthwhile so I binned it off.
Oh, so I misread your sentence. Thanks for the clarification. Sorry for the noise.
The only way I can think to handle this is if you've got a really thorough test suite in Selenium or similar. Do a before and after, capture screengrabs of everything and flag up where the 'new' CSS has caused visual differences.
It's a horrible solution but then it's a horrible problem.
Especially since it'd be an optional build step you'd only want to run infrequently.
That would have the advantage of supporting complex webapps written in any language/environment.
As important as what classes were used is what classes were in the HTML, but didn't exist.
Instead of manually clicking around a webapp, you could do a test suite. This gives another way to measure test coverage.
I assume we have to wait for a browser vendor to do this? I haven't seen any plugin/extension feature that reaches this stuff.
Then again, we have good open source browsers...
Or styles for a CMS module that is currently not in use (e.g. for open positions in a company).
I wonder what the least used, yet still used CSS is I ever wrote (relative to project traffic). Maybe some feature a Client requested, I knew he would never really use, but he insisted on (deep linking to some modal for a facbeook post or something).
Every visitor had a small probabillity it would run the code, and after a couple of million visitors, they had a pretty good idea of what styles were unused.
A large user base would give you decent coverage.
It is, though, limited to the context of a single page. You can't browse several pages and then see what the net unused css is.
I believe, though, extensions can talk to dev tools, so there's some plausible way to extend it.
My impression is that number of requests is a more critical optimization than file size (at least when serving CSS sized files)
Thankfully frontend pipelines like React + Webpack makes it fairly easy to test this out. We spiked out generating individual JS + CSS for each view but ultimately found it wasn't worth it - individual views amounted to very little code with the bulk of the filesize taken up by the common 'core' of our application, and dependencies. We scrapped this specific idea.
What we did end up doing, however, was create a seperate stylesheet just for things required on the very minimal landing page and inject that straight into the <head>, which gave us significant speed improvements.
Webpack is super handy like that - no need to be aware of this and manually keep track of a seperate stylesheet :)
A fairly safe default starting point would be:
1. Tiny subset of inlined critical CSS (See https://www.smashingmagazine.com/2015/08/understanding-criti...) 2. Asynchronous + rel=preload loading of the main CSS of your site 3. Then, if there are hefty chunks of CSS for specific pages only, bring those in on those pages.
This changes a bit if you're using HTTP/2. Then the multiplexing makes it beneficial to break the CSS into a few smaller files instead of one big one.
In the end, you probably just have to experiment and test. :) No guaranteed "this is best" approach here.
As an added benefit, you'll get de-duplication, minification, inlining (with fallbacks) and, with a little work, image-spriting thrown in almost for free.
If you want to play around easily, take a look at https://github.com/assetgraph/assetgraph-builder
Nonetheless, it is a challenging and fun problem to solve.
Edit: seems overkill, the theoretical solution I had in mind would just take a few arguments;
ie:
trimCss mybloated.css mypage.html > mytrimmed.css