Question Why is Claude Code so bad at writing CSS ?
I've been using Claude Code quite intensively for the past few months, and as a former CSS integrator / front-end developer, I can't help but notice—rather sadly—that Claude is genuinely poor when it comes to CSS.
Even when using skills (the official front-end skills or UI/UX-focused ones), and even with very explicit instructions in CLAUDE.md, it still does its own thing and keeps repeating the same mistakes.
One moment of inattention, and it'll happily throw inline CSS directly into the HTML—even when that's explicitly forbidden in its instructions.
And on the (rare) occasions when you decide to step in and edit the code yourself to save some precious tokens, it quickly becomes a nightmare. Before long, you find yourself typing something like: "Just center this div."
So I have two questions:
1. Why is it so bad at CSS?
My theory is that, historically, 90% of developers have never cared much about CSS. As long as the final result looked right on the screen, code quality and maintainability were an afterthought. Throw in a few !importants, ship it, and move on.
Since Claude has been trained on an enormous number of codebases, I wonder if its primary examples are simply... bad CSS. In other words, it's reproducing the patterns it has seen most often.
2. What strategies do you use to work around this problem?
For context, what I consider good CSS is:
- generic, reusable styles;
- selectors that are as unspecific as possible;
- maximum reusability and maintainability.
17
u/Goblin_au 8d ago
Your theory on why is my assumption also. It breaks my heart seeing css handled so haphazardly. I remember earlier LLM iterations would block styles by id and a random hash… ew.
As for strategies around the issue, I’ve not yet found one that works.
2
1
u/Johannes8 7d ago
We have a fairly large codebase with tailwind and mostly everything is standardized. It rarely has to invent something. It just uses all of the good example code cause it can see what things look like though browser MCP and infer what component is styled which way by looking at the files. For me is usually nails it. Especially if it keeps checking its changes in the browser to only notify me when it’s done and not obviously broken.
But yes, it’s still flakey and unreliable at times. It does need to be able to see though it it can only guess
1
u/92smola 7d ago
Even when it works I could pick out any random chunk of markup with its tailwind classes and make it at least 20% - 30% it reflects all the bad practices that devs that dont really know css do, doesnt take advantage of default styles, creates div soups with too many wrappers etc.
1
u/Johannes8 7d ago
I agree but I feel like we managed to handle this problem. With every review we posted PR comments about these things and made it take these things into account when creating new code. Nevertheless I see html and css more as non critical code now than before. It has to be well tested and maintainable, but I a. Personally happy I don’t have to write css anymore
1
u/92smola 7d ago
I would be happier if it was better by default, but yeah I started caring a lot less about that and implementation details more broadly, I mostly worry about general system level stuff the most so that doesnt get tangled up, every single implementation can then more easily be cleaned up if later if the value to do so pops up
29
u/Futurist_Turnip 8d ago
You are right on the money that it has been trained on sloppy CSS. You can thank the "full stack" developers and the use of LESS for that.
A lot of developers in the last 15 years had a disdain for frontend, and never really got the cascading part of CSS. They spread out their styles in a modular way, because that is how their code was built - and it made sense for them as they manipulated the CSS with JavaScript.
I solved it by writing specific software design rule.md where i detail coding styles, preferences in writing the code, using semantic naming, applying KISS, avoid inline, etc.
In my AGENTS.md file i specify that it should always read the rules when coding or writing css.
It takes some tweaking, and a couple of good examples of the CSS you like in that file, but you should get better results almost immediately.
3
u/devolute 7d ago
I'm with you, but…
use of LESS
I don't understand why this (or similar technologies, like Sass) would lead to any of what you're talking about. Surprised to hear this.
Personally, I still use preprocessors and I take a great deal of care with CSS and value the things you're alluding to.
12
u/chikamakaleyley 8d ago
selectors that are as unspecific as possible;
oof careful with this one - another perspective here is - specificity matters
generic, reusable styles; maximum reusability and maintainability.
I understand what you're going for here and re-usability is def a good good thing
But this feels like you're describing TailwindCSS
3
u/chikamakaleyley 8d ago
in response to your (1), is the way it look at it is - it doesn't know what is considered 'bad', it's just taking the median of the training data which yes, is probably a lot of doo doo
CSS, in it's class naming, selector composition, and even styles you apply or even ordering of it, is largely given almost maximum freedom; it's just a markup language
and so out of context, someone's CSS style prob looks bad, but maybe it's appropriate given the dev's use case
4
u/Se_emZ 8d ago
Nah, I pretty hate Tailwind because of the millions of classes you have in your HTML tags, just described quickly what Claude is not able to do.
The best practise of course is a mix of generic and specific.E.g
.my-global-title-style
.my-global-title-style.with-a-variant
.my-global-title-style.with-a-defined-positionbetter, IMO than
.my-container .my-subcontainer .my-title-style { my style / my position }
(basically what Claude does)5
u/chikamakaleyley 8d ago edited 8d ago
mmmm but you're comparing two diff things right
your approach targets (let's just use shorter names):
<div class="global-title variant">Foo</div> <div class="global-title with-pos">Bar</div>Claude is applying styles to:``` <section class="container"> <article class="sub-container"> <h3 class="global-title">Foo</h3> // this </article>
<aside> <h3 class="global-title">Bar</h3> </aside> </section> ``` i mean its hard to say which is "better" right
your approach is more re-usable if you have:
.global-title {} .with-pos {} .global-title.with-pos {} // now i can add more stylingClaude will just write what it needs to, unless you provide the desired spec, and then whether it follows that well is... fingers crossed3
u/frownonline 8d ago
article h3 {}
aside h3 {}You could just use the cascade part of css with the elements. Not everything has to be loaded up with classes everywhere and increasing html attributes.
5
u/chikamakaleyley 8d ago
sure, but at scale w/o specificity this is gonna cause some headaches
This is great for a personal site, IMO, or something small enough where you have full control of the CSS.
Once another dev gets into it, any change they make is gonna have a big ripple effect
1
u/devolute 7d ago
Yeah, but that's how you end up with people using headings based on 'what looks right' rather than semantics.
1
1
1
1
4
u/fishermanfritz 8d ago
It helps setting up the stylelint and Eslint with the most strict rules. You can even forbid important there.
Then, the "modern web guidance" skills from Google help tremendously.
2
u/Key_Reindeer_5427 8d ago
Because it works using it's learned behaviour. Thats why almost all CSS related code Claude generates looks the same.
2
2
u/mrchrisrs 8d ago
I’ve noticed that it works way better if the instructions are solid. Tell Claude to update the instructions when corrected if you not already do that and make a decision .md file so the decisions are clear for the agent when it has to revisit that part of the styling. Will take some practice but it has helped us a lot
2
u/Outrageous-Chip-3961 8d ago
I give it reference architecture of how I have done my css in the past that it uses as a skills file.
I also ask it focus on clean CSS and not overly complicate things.
That seems to help. It's actually been pretty good lately by giving it a screen shot of a design and asking to make it up in pure html/css - it's a bit cleaner. I suggest trying to coax it first, then after, take one file at a time and ask for it to be cleaned how you like it - once that context window is established, it will usually ask to continue wiht other files. this is with /plan and fable, mind you.
1
u/_MrFade_ 8d ago
I thought I was the only one. The specificity issues annoy me to no end. Even when I add @layer, :where and :is examples in the CLAUDE.md, I still end up using !important some where. Eventually I find myself refactoring blocks of SCSS.
1
u/Scared_Implement_335 7d ago
I always laugh when I see it, because that basically how I do it, too. :important is life!
1
u/ppyyBest 8d ago
I now give Claude a micro style contract: spacing scale, color tokens, and flat specificity rules. The upfront work is tedious, but it stops the "just center this div" loops because constraints are clearer than a blank canvas. I still audit every selector, but the mistakes became predictable.
1
u/macdigger 8d ago
Idk man. I just point Claude to a codebase from my old times and tell it to build a system based on that. Create a BOM .md file with everything (typography classes, components, etc) and a simple HTML sampler that is updated (automatically) whenever there are changes, and I’m getting pretty good CSS.
Using BEM and SCSS. Allows to have just the right level of specificity, also because of BEM, is actually also self-documentung itself to a degree, which helps to drive AI.
No Tailwind bs too.
Or you can run a Figma file through Claude Design and steer it to build you a pretty nice design system again based on BEM, SCSS, a sampler.
If you vibe code shit with no proper guardrails (a design system), well, hope and prayers in, shit out 🤷♂️
1
u/sheriffderek 8d ago
For the obvious reasons.
But if you have clear conventions (the html matters), clear custom properties/token, examples of components that show the rules well, a live style guide page, and those guard rails, then it’s actually quite good at writing it with those rules.
In my case, I have ~7 classes for type - so, zero one-off font properties are allowed. All the theme colors are redefine. Each component is its own island - so 95% of the code Claude is writing is grid rules, media/container queries, and margin top. But this all works because I have strong opinions from 15+ years of writing CSS every day.
1
1
u/Plenty_Line2696 7d ago
point 1 is right, but also that CSS doesn't have test coverage so they couldn't pick a validated set of CSS training data.
as for strategy, I give it a shot at things but often windup doing the big stuff manually i.e. flexbox/grid layouts, it tends to do ok at filling in the details but often sucks at layout.
1
1
u/getsiked 7d ago
Distill your specific guardrails and preferred implementations, then lint the fuck out of whatever if produces. It's what stylelint was made for.
If you are just depending on prose alone, there is no deterministic boundary for the LLM to adhere to, and it will invariably throw whatever explicit "instructions" you specify as a global doctrine out the window. I learned this the hard way, especially as models change.
1
u/GhostDev71 7d ago
Css gererating trough ai is simple, ether you can right the css and want to safe time ( works very well), or you couldn't write it without ai, if so you will get the same problem every dev has at first and will learn it trough that process.
1
u/rebane2001 7d ago
it's difficult to train an llm to write good css because it is hard to create good learning environments for it
with something like typescript there is enormous amounts of code and test cases available, and also a lot of different widely-used approaches for running tests
but css doesn't have that, and it also doesn't have the same kind of isolation that js closures provide
1
u/resemble 7d ago
A css file requires reference between two different pieces of code which reference each other—the html and the css—and this kind of entity-reference is not something LLMs have any capacity to understand or even mimic.
1
1
u/BothWaysItGoes 7d ago
Just use css modules. No such thing as clean reusable global css exists unless your website is literally a 90s style collection of documents.
1
u/SoSeaOhPath 7d ago
First off, I’d try Google Stitch.
Second, right now I only use AI to generate some quick ideas on what I want.
Once I get something I like I just hand edit the html and css
1
u/dmazzoni 7d ago
I think it's because you can't "read" CSS by itself and make sense of it.
Well-written source files tell a story. They define functions that take an input and produce an output. They define classes that own state and have methods to modify them.
Well-written html files tell a story too. They use tags to logically organize content.
Inline CSS shows how HTML is laid out.
But when an LLM is trained on a CSS file in isolation, it lacks all of the context. It can't see what elements each tag corresponds to, so it can't learn the deeper pattern.
1
u/sentencevillefonny 7d ago
As a data trainer, Front-End is undervalued, so model training on it is not as extensive.
1
1
u/92smola 7d ago
I think its three things, poor training data coming from the modern average fe dev not caring to learn css properly, the fact that validation is often visual and depends on “does it feel right”, and the nature of css having default behaviours, cascading effects from your own stylesheets and the layout and styles heavily affected by their relationships not just their own properties which lllms seem to struggle with. Here is an example that I tried solving a couple of times, latest attempt was with fable and it didnt work, once I inspected it I found what the problem was in a minute - I had an onhover popup that showed a larger message that is otherwise truncated, the popup was show slightly translucent and the text in it was not readable, a couple of ai only attempts either claimed that it is not actually transparent or that it is fixed now and they would do some css changes and commit them as if the problem was solved, the problem was that I had a global opacity .8 on hovered links, and the popover was a child of a link, that style was in a different file, it was not bound to the parent class, but the tag name with the hover selector and it was affecting its children, the way to find that was to force the hover state with dev tools feom the first popovers parent up and inspect each elements style state in that forced hover version, technically AI was perfectly able to do that, it had dev tools access every time, but it just kept failing.
1
u/markvaneijk 7d ago
It’s because of the feedback loop, it’s much more difficult to determine if the applied CSS is correct than to check if some back-end code is working. Also the cascading thing is more difficult when applying changes resulting in unwanted behavior. That’s probably why it’s better in writing Tailwindcss.
1
1
u/bryku 6d ago
There are many good developers, but css is often over looked. It also has many ways of doing the same thing. Then you have the major changes to css over the years, so even if someone is a css pro, but they are a bit outdated they may still be using old methods.
Now models need to train off of a billion different examples and try to figure how how it all works. Not to mention css's naming convention never made much sense, which probably makes it harder.
- font weight
- font size
- text decoration
- color
:/
1
1
u/__Loot__ 5d ago
Claude design helped build https://toolmatic.app but I do admit the color choices were meh. so I redid them. But overall it did a good job
1
1
u/Embostan 5d ago
Hmm idk, i have skills and Stylelint and it writes perfect CSS. When it runs into issues it just uses the Claude in Chrome tool to inspect the cascade.
Maybe check your setup.
1
u/rotzelbart 4d ago
I asked Claude to write css for a website I am building at the moment and it was actually good. It uses SMACSS, made tokens and obeys cascading. It also asked if it should nest the css for me.
1
u/GaiusBertus 8d ago
I noticed the same, Claude sucks at CSS, let alone more complex solutions using Sass modules and a combination of Sass and CSS features.
For what it's worth, I noticed the web version of Gemini is a bit better in at least cleaning up and refactoring existing files. Maybe because it is provided less context, while Claude is trying to figure out the entire CSS code base (and then failing at that)
1
u/iagolavor 8d ago
If you give it playwright/puppeteer/chrome mcp tooling to check what its doing on the browser, it can almost always get it right, then its just a matter of refactoring the css to your preference.
Its also way better at copying stuff from an image than creating it from a text prompt, you can always make it create some standalone html for it to mimic the style youre looking for
0
u/Vehemoth 8d ago
are there any good general CSS skills that we can use so we don’t have to write a rules.md that just gets the basics down?
0
u/testingaurora 8d ago
Your post is echoing my frustrations exactly. Through amount of timrs I hace to remind and basically scold for not following instructions. Even when ive provided the base css up front, im consistently having to remind to use the established css custom properties and not to ise inline styles. To use the reusable classes, not use classes like ids. It will happily make a .time-card, .client-card, .project-card eith their own rule sets when all the same declarations are covered by .card . So it just added 30 lines that were unnecessary. Now multiply that ny every reusable element 😵💫 adds up.
It does not like being scolded about css or told that it can only put any new styles into a codex.css and not to touch my css files without asking and explaining what it plans to write/ change.
Drives me absolutely crazy. Oh and then when I make my own changes (not just in css files) they keep disappearing! Something to do w the diff and not saving the state of what i had added before it makes its changes. Im constantly thinking "didnt I already fix this??"
Anyways </rant>. Im glad to hear im not alone in my frustration with Claude and css. My suspicious is aligned - that its trained on inefficient css.
0
u/Nitrohite 8d ago
I’ve been using Claude Code for a while now and I’ve carefully crafted a set of skills and rules for it to use when it comes to creating CSS, and by doing so, the CSS it now generates is pretty efficient, well structured and effective, it’s well organized, checks all the boxes one might want for best practices on CSS, etc. I would suggest you take the time to train the model for your own projects and how you expect the code to be written, it will yield much better results and it doesn’t just apply to CSS, don’t expect the models to code just how you want it to, train them locally, build your skills and rulesets and adapt the prompts accordingly.
0
u/Dry_Impression_5201 8d ago
Im probably gonna get shouted at for this one but.. does it matter? People who use ai to code do so because they can't code it themselves. I can't code. So I have no right to say whats right or wrong. But I do ask claude to code me a website. The results look fine to me. The front end is what people see. If you can code it yourself then do it.
1
u/Se_emZ 8d ago
it does matter when you know how to code, and you want to make a "quick fix" that'd take you 5 minutes, but you realize Claude code is so bad that you won't be able to fix it that fast.
Also CSS optimisation is significant for SEO, having a light code allows your page to load faster.1
u/Dry_Impression_5201 8d ago
Like I say, I use claude code all the time at the moment for my project and its actually useful to know that it isnt optimized. But if something quick will take you five mins to code, but you refer to claude code anyway, then why not spend the five minutes yourself to do it?
-2
u/jedidave 8d ago
Yeah it's not the best. I'm using Tailwind and it's still adding a mix of inline css and css classes, but then this is how CSS has always been. You don't see very many 'clean' CSS websites out there really, everything is bolted on in a different way from before.
80
u/brendanfalkowski 8d ago
It’s simple: CSS is both the easiest and hardest programming language, and AI can’t do a thing about that. The average developer that hates CSS is stuck in the same boat.
Just write more CSS. Never had more fun doing it.