
UnCSS: Remove unused styles from CSS - rodrigocoelho
https://github.com/giakki/uncss
======
ry_ry
Have used tools like this before, and invariably end up accidentally stripping
styles from an <insert JS UI lib> component with a dynamically assigned
className or something equally silly.

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.

~~~
vog
_> with a dynamically assigned className or something equally silly._

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.

~~~
ry_ry
Oh dynamically setting class isn't silly, but the times i accidentally removed
the 'unused' style because it's not explicitly coded into that app and was
flagged by the tool, I felt pretty silly!

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.

~~~
vog
_> Oh dynamically setting class isn't silly_

Oh, so I misread your sentence. Thanks for the clarification. Sorry for the
noise.

------
jwr
I've been hoping someone would write a similar tool, but using a browser, so
that I could run a webapp, click around (using a checklist, to cover all of
the views) and get a resulting list of used CSS rules from the browser.

That would have the advantage of supporting complex webapps written in any
language/environment.

~~~
aslushnikov
There's a "Coverage Support" experiment in Chrome DevTools which does css + js
coverage in a way you describe it. The CSS part was shown on Chrome DevSummit
2016 [1]

[1]
[https://www.youtube.com/watch?v=HF1luRD4Qmk](https://www.youtube.com/watch?v=HF1luRD4Qmk)

~~~
laurencei
Starts around the 18min mark in the video.

------
AliAdams
I wonder what the performance increase would be of loading one big CSS file on
the first page load and serving from local cache from then on, vs loading a
smaller but different CSS file for each page you visit.

My impression is that number of requests is a more critical optimization than
file size (at least when serving CSS sized files)

~~~
madeofpalk
It's going to depend a lot on the type of site you're building.

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.

~~~
madeofpalk
Just to clarify (after I've re-read my comment) - we didnt explicitly create a
landing page stylesheet, instead we were able to use Webpack to automatically
create a seperate stylesheet at build time containing just the styles used in
the dependency tree of the landing page.

Webpack is super handy like that - no need to be aware of this and manually
keep track of a seperate stylesheet :)

------
msiebuhr
AFAIK, this could also be written as a transform in AssetGraph
[[https://github.com/assetgraph/assetgraph](https://github.com/assetgraph/assetgraph)],
which does all of the loading, parsing and traversing for you. At least the
given description reads like the internals of the population/loader-system in
AssetGraph.

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](https://github.com/assetgraph/assetgraph-builder)

------
dalkur
I've done something similar nearly two years ago[1]. The problem is rather
difficult, especially with all the JavaScript frameworks in existence right
now. I've tried to build a state machine for handling those frameworks but
never got around to finishing it. There's basically and endless amount of
combinations one can do, thus you probably want to limit depth or something.
You also have to be able to detect ::after and similar kind of selectors,
which isn't always straightforward with querySelector and needs quite a bit of
cleaning. I ran into a few other (edge) cases, which I cannot remember right
now.

Nonetheless, it is a challenging and fun problem to solve.

[1]: [https://github.com/Kevin-A/css-detector](https://github.com/Kevin-A/css-
detector)

~~~
egeozcan
My naive opinion is that this should be done by the browser, perhaps in the
developer tools. You would be marking a session as "integration tests" and at
the end it would give you a simplified css file without the unused rules
during testing.

~~~
dalkur
I wholeheartedly agree with you. That would be the ideal solution, because the
browser is already doing the passes over the CSS rules.

------
robotjosh
This is a problem I thought would be solved by 2017

------
mrschwabe
Clutch timing! Been working on several projects amassing a multi-purpose
stylesheet (currently ~600 lines) having already conceded that a tool which
accomplishes exactly this would be needed.

Edit: seems overkill, the theoretical solution I had in mind would just take a
few arguments;

ie:

trimCss mybloated.css mypage.html > mytrimmed.css

------
booleanbetrayal
I've been wanting to tie this up with Casper automation in order to get
coverage on dynamically generated content. The hard part is just ensuring the
content path is adequate. We do something similar with PhantomCSS already, but
it's definitely a tighter scope.

------
eloff
Finally! I've been wanting this for a decade - but not badly enough to try to
build it myself.

------
asimpletune
I made a similar tool, although it doesn't load the page in a browser to
remove unused styles.

[https://www.npmjs.com/package/uselesscss](https://www.npmjs.com/package/uselesscss)

------
KevanM
How easy would it be to get this to work with something that spiders a site,
so it generates a CSS file dynamically for a whole site instead of manually
feeding it URLs?

------
thora
This is great! I'm happy to see PostCSS proving to be a creative platform for
web development.

------
Grangar
Would this work if you print classnames with php?

~~~
cmg
Sure, you'd need to point the files argument at your website on a server,
though - you couldn't just target a .html file.

------
bl4ckdu5t
Am I missing something? UnCSS has been for about 3 years now.
[http://bit.ly/uncss](http://bit.ly/uncss) by addyosmani

~~~
scandox
I guess this is being downvoted because he links to the wrong repo (i.e. the
grunt edition of the same project) but the point seems fair. I've been using
unCSS about 2 years so it is interesting that this discussion is happening now
and that people seem surprised by its existence. Perhaps just a symptom of too
much JS everything.

