Hacker News new | past | comments | ask | show | jobs | submit login
Tools for Auditing CSS (css-tricks.com)
90 points by starbist on April 1, 2021 | hide | past | favorite | 32 comments



Hmm... I wonder why stylelint wasn't mentioned? [1] I thought it was nowadays kinda the CSS equivalent to ESLint.

We added it (in tandem with Prettier) to a codebase that uses lots of old SCSS. So far it's been a good gatekeeper as the team has been growing, blocking the most questionable .scss edits in PRs. We had to disable and ignore many of the rules to fit it together with our legacy files though.

[1] https://stylelint.io/


Linting tools tend to be a combination of rules that make your code nicer to look at by some relatively arbitrary stylistic convention and rules for keeping out code that because of the nature of the language can lead to footguns.

Stylelint in my experience is almost all, if not all, about enforcing stylistic convention. I can't stand it because I do not find most of the stylistic conventions enforced to actually improve legibility.


I agree with the sentiment but as other user pointed out, there are quite a few rules that can enforce very strict limits on css selectors complexity : limiting sibling selectors, descendants, limit combined ( eg. .foo .bar .baz = 3 parts ), low specificity even down to 1, disallow ids, !important, etc.

This requires in my experience using a consistent bem syntax otherwise specificity snowballs pretty fast.


why is disallowing id's a feature? it makes headless testing so much more easier, amongst other things.


Ids overpower everything else in the css cascade, in particular any utilities like tailwind’s (unless you activate !important for utils, which also has its cascading effects and heavyhanded fix).

Using an id is not inherently wrong, and with stylelint you can always disable a rule for the exceptions, with a comment of the form /* stylelint-disable-next-line <optional specific rule id> */

Nowadays esp. with composition methodology it’s almost always better to just use a unique bem like class, eg. .HomepageHero-carousel , even if the element in question is a "singleton"... because later someone can stick a mb-4 on it, or a text-lg , or even your own custom utility or modifier and it will stick, without snowballing css selector complexity.


I didn’t understand your reply at first. If you use ids for easy targeting parts of html, then it doesn’t matter, stylelint doesn’t check the html.

Applying styles can be done via classes so the css selectors in your stylesheets do not need to mention any #ids.

Applying styles with #ids however, is an issue.


In my experience there are a fair amount of rules in the second category of yours (anti-footguns). For instance, preventing invalid properties alone is a huge one. There are also rules like [1], a few violations of which popped up in our legacy styles. No dev of ours would've caught those.

[1] https://stylelint.io/user-guide/rules/no-descending-specific...


hmm, maybe it's just that I am only being caught out by the styling rules, or maybe it is that I am pretty good at understanding the cascade so the linked example is actually something that - while probably a footgun - for me is likely to be annoying because I actually wanted to do what I did.

But I guess deploying a footgun is often a minimum two person job:

first person writes code that when used wrong will shoot in foot but they would never use wrong, next person actually pulls the trigger.


What’s missing is postcss-bem-linter

With it you can actually enforce bem like syntax, low specificity, so your scss plays well with the utility / composition methodology eg. tailwind but also custom utilities.

https://github.com/postcss/postcss-bem-linter#preset-pattern...

SuitCSS setting for postcssbemlinter is very good for vue/react components, less subjective imho than "block element", its "component root, descendant" instead.

https://github.com/suitcss/suit/blob/master/doc/naming-conve...

You declare the component for which the following css applies, eg /* @define UserAvatar */ , so the linting is far more useful. You’re linting the classnames to enforce consistent naming based on components, not just a stylistic choice.

Unfortunately it takes some work to setup a strict stylelint config and properly configure postcssbemlinter, maybe i should post mine as a gist ... there is no premade config afaik, I think very few people used this kind of strict linting... tailwind became succesful and people saw it as the solution, and completely disregarded the middle way in the process as if writing custom css was inherently bad.

Tbh many stylelint base rules seem pointless, like complaining about #ffddee should be written #fde..m who cares? Minifiers take care of this.

Sadly postcssbemlinter + Suitcss setting is a bit buggy around tailwind directives like @apply, but it’s functional enough used it two years on a nuxt project, with a strict low specificity config it really helped me rethink how to simplify selectors and avoid css spaghetti.

TLDR i feel like a thorough bem/bem-like linter is what’s missing from most projects still using scss, because i’ve seen some really awfull bem css, it’s not enough to have a guideline, it needs strict checking to improve css quality.


My tools for CSS are my eyes and bunch of browsers. No matter what I do (LESS etc.) something always gets messed up at the end.


Is anyone aware of a tool that would allow me to manually walk my entire app and any css that doesn't get used can be flagged for deletion?

I find that even with well behaved libraries and tree shaking, my output css still includes a lot of stuff I don't need. (Eg. Yes I use Foo.Button but I don't need all the css for the styles of Foo.Button I never use like circular or large or withIcon)


Chrome has a css coverage tool built in[1]. I suppose it's tricky though, since some html is only visible if there an error (error boxes, etc), or only visible in some rare state (logged in as admin, etc).

Screenshot of it looking at unused CSS on HN: https://imgur.com/a/TLywsv5

[1] https://developer.chrome.com/docs/devtools/coverage/


Mhh I am sure it could be possible to walk the app with cypress or puppeteer while raising this coverage.


Huh. I wasn't aware. Thanks. I'll have to see if there's a sensible way to get the results in a format that can be used to progrmatically cull a build output.



Tailwind has this built in if you're open to a new framework completely: https://tailwindcss.com/


Tailwind drastically reduced the overall size of my CSS bundles. And it stopped that inevitable, gradual CSS bloat that I used to see on longer lived projects too.


isn't it postcss/purgecss doing this on tailwind's behalf?

this process also strips styles that are not in the actual html/template files being scanned and are only shown in error paths or in some other way.

it also strips styles applied directly to tags (without class).

i find it quite messy to maintain purge ignore lists and making extra-extra sure that the removal regexp is correct as it can remove valid classes added/removed by templating libraries like jinja.

proper css coverage is more than a glorified grep that looks for all the tailwind class names...


Don't use Tailwind, it's garbage.


Personally I’m not in favor of CSS in classes, so I wouldn’t use tailwind given the choice. But tailwind does look like a perfectly fine framework if you are into that sort of thing. I don’t claim to understand people that want to write all their styles in the class attribute. But if you do, I don’t see a reason why Tailwind would be garbage. In fact it looks like a perfectly fine tool for a workflow that I personally don’t use.

Do you have a personal experience you would like to share?


Can you please elaborate?

Personal anecdotes, development experiences that made you feel that way.


I really don't like how it handles responsive design, but that could also be because I work more on apps than marketing sites. First, fixed device breakpoints doesn't seem like the way to go, I find I need more customized breakpoints that are based around the UI rather than having general phone/tablet/desktop breaks. Then because you are applying styles to each element for each breakpoint, its very hard to look at and comprehensively think about a single breakpoint's layout. I can see where this works for making minor changes here and there, but major layout changes with breaks are almost impossible to keep in your head.

Then with flex box it lacks a great deal of customizability when it comes to controlling how space is distributed across elements.

And somewhat bigger picture, I'm looking to use less tooling and preprocessing, not more. CSS has come a long way to where we can now get rid of SASS, but instead Tailwind is replacing that step with fullying buying into the whole webpacker tool chain. If you're already really into webpacker that's not a huge issue, but brining along node and webpacker just for a CSS library is a bit much.


That's a hot take


So hot it's almost 20 years old!


Care to provide any reasons?


PurgeCSS is a tool to remove unused CSS styles https://purgecss.com/


I think Svelte does something like that by default. I would love to see more frameworks pick this up. I think it wouldn’t bee hard for e.g. Vue or Stencil to do something similar since they have their own compilers.


I've struggled with this as well. As far as I can tell there isn't a good solution, but I'd love to be proven wrong.

You can run PurgeCSS in a dry mode to find any unused selectors, but it can't handle any classes that are dynamically generated. If your codebase has used anything like `buttonClass = 'button-' + color`, you may get false positives.

The Chrome Dev Tools coverage can show you how much of a stylesheet is used at runtime, but if you concat everything into a single css file that's used for every page, a single page's usage doesn't help.



Yeah, I do like working with Tailwind and PurgeCSS and that setup works great. It's a good way of avoiding the unused CSS problem in the first place.

The problem for me is digging into a large existing codebase which has built up thousands of semantic class names and a bunch of nesting in the CSS. I'd like a tool that could tell me what's probably not being used, which I could then use as a starting point for some clean up.


There are various browser extensions that do that. Chrome Dev Tools has a coverage tab to do something similar.

https://developer.chrome.com/docs/devtools/coverage/


That's why css in js is much better. Once your html is out, css is also out.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: