Style Convergence: Don't Ship Eight CSS Kits for One Button
Why styles proliferate, how to fold them into design tokens in batches, and which differences should stay
THE QUESTION THIS PAGE ANSWERS
ANSWER FIRSTWhat is the key idea behind “Style Convergence: Don't Ship Eight CSS Kits for One Button”?
Why styles proliferate, how to fold them into design tokens in batches, and which differences should stay
Turn taste into a behavior the product can repeat. The useful outcome is not a nice opinion. It is a visible rule, a small example, and a way to tell when the experience falls below the bar.
Capture one before-and-after example that shows the quality bar without extra explanation.
Polish that improves the surface while leaving the user's uncertainty untouched.
This simulates a real project's iteration. Each click of "Add another feature" is you opening a new conversation and asking AI to build a page. Watch how it handles the button each time, and how the four numbers below climb.
The project is still empty. Click the button below to start iterating.
After eight rounds, look at this pile of buttons — you can't tell which one to edit. That's the feel of "loose parts."
Reinventing styles isn't the model being lazy. It's three structural reasons stacked together. See the reasons, and you'll know where to put the gate.
Your CSS isn't in front of it
A new conversation only has the few files you just handed it. It has no way to know the project already has .btn-primary, so it writes a fresh one for the request.
Writing new is cheaper than reading the old
Understanding an existing style means reading every related file, plus worrying that a change will break something else. A new class name is zero risk and zero reading cost — that's its optimal solution, not yours.
Afraid of breaking things, so it adds a parallel copy
When it needs a button with a shadow, it would rather write .btn-primary-new than change the original — editing a style others already use is high-risk, so it picks the safe path that proliferates.
All three reasons point to the same thing: it's missing a list of "what we already have." Write that list into the project rules file so it can see it every round, and the proliferation stops. Same idea as Lesson 8 encoding environment facts in a Rule — this time the asset is styles.
Don't expect one big refactor to clean up a messy project. Follow these four steps — you can stop and verify after each one.
Inventory — look, don't touch
Have AI scan the project's styles and produce a duplication list: which classes implement the same control, how many color and radius values are scattered around. No code changes in this step — first see how much debt you owe.
Set tokens — fold magic numbers into a few tiers
From the inventory, pick the values actually in use and lock them into a small set of variables: primary color, semantic colors, two or three radius tiers, four spacing tiers, control height. Few tiers — few is what you can defend.
Merge in batches, one control at a time
Buttons first, then verify; cards next, then verify; then inputs. Commit each batch separately so you can roll back one batch if something breaks. Convergence is an equivalent replacement — visually nothing should change. If you actually need a new look, that's a different task.
Set a gate so it doesn't grow back tomorrow
Write this into the rules file: "Before writing a new style, search tokens and shared components first. Reuse if you find one; only create a new one if you don't, and say what you searched." Without this gate, you'll be cleaning up again in three months.
The easiest place for convergence to go too far is flattening differences that should exist. Five real style pairs — you decide which were piled up by accident, and which have a reason.
To decide whether to merge, ask one question: what is this difference called? If you can name it, keep it — "secondary button," "destructive action," "touch-target minimum," "overlay one tier above the card." Those are design decisions; write the reason in a comment. If you can't name it, merge it — two radii 2px apart, two blues the eye can't tell apart. They aren't called anything. They were written on the fly.
The consistency lesson in the Taste series says the same thing: difference isn't a crime — having no reason is. That lesson covers how to set the variable table from the design side; this one covers how to pull things back once the code has scattered. Read them as a pair: one gives you the standard, the other gives you the surgical plan.
Further reading: Taste Engineering · Consistency: Where System Feel Comes From (how to set tokens) · Previous lesson: PlayGround (where to tune components after you converge)
Big-bang full rewrite
Tell AI to "unify the site's styles" and you'll get a 60-file diff you can't review and don't dare ship. Always batch by control.
"While we're here" visual tweaks
During convergence it often "optimizes" the radius and palette while it's at it. Then you can't tell whether the page looks different because of a merge bug or its aesthetic improvisation. Convergence is equivalent replacement only.
Tokens too fine-grained
Twelve radius tiers and nine grays is the same as having none — next time it still has to pick, and it will pick wrong. Tiers only constrain when there's almost nothing to choose from.
AI will not reuse what you never told it exists. Styles proliferate because it forgets every round, so the fix has two halves: fold the mess into tokens by control, and block the future with one rule — search before you write. The Skill at the top of this page is the executable version of both halves. Copy it to your Agent; it will hand you a debt inventory first, instead of starting to edit.
The companion rule is "check for duplicates before adding a feature" in the itshen/xs_vibe_rules repo. This lesson extends that from features to styles.
Turn the feeling in “Interactive Demo 1 · Pile Up a Heap of Buttons Yourself” into a judgment
“This simulates a real project's iteration.” points out that AI has lowered the bar for making something usable. The skill readers need is noticing what is wrong and turning that feeling into an actionable requirement.
Watch the user's next action, not just the surface
Turn “The project is still empty.” into observable questions: does the user know what happened, what to do next, and how to recover from an empty or failed state? Does the hierarchy make the important information visible first?
Pretty is not the same as usable
Apply “The companion rule is "check for duplicates before adding a feature" in the itshen/xs_vibe_rules repo.” to a second screen or flow. Record one moment of hesitation and the user action after the change; observable behavior is stronger evidence than polish alone.
From “Interactive Demo 1 · Pile Up a Heap of Buttons Yourself” to “Don't rush to blame AI — the environment forced its hand”
“Interactive Demo 1 · Pile Up a Heap of Buttons Yourself” grounds the problem in “This simulates a real project's iteration. Each click of "Add another feature" is you opening a new conversation and asking AI to build a page. Watch how it handles the button each time, and how the four number…”. “Don't rush to blame AI — the environment forced its hand” then moves it toward “Reinventing styles isn't the model being lazy. It's three structural reasons stacked together. See the reasons, and you'll know where to put the gate”. Together, they show that the lesson is not just a conclusion to remember, but a claim with conditions.
Carry the judgment into the next situation
For experience work, turn abstract impressions into user actions: did the person understand the state, find the next step, recover from an error, and want to continue?
- “Interactive Demo 1 · Pile Up a Heap of Buttons Yourself”: This simulates a real project's iteration. Each click of "Add another feature" is you opening a new conversation and asking AI to build a page. Watch how it handles the button each time, and how the four number…
- “Don't rush to blame AI — the environment forced its hand”: Reinventing styles isn't the model being lazy. It's three structural reasons stacked together. See the reasons, and you'll know where to put the gate
- “The closing point”: All three reasons point to the same thing: it's missing a list of "what we already have." Write that list into the project rules file so it can see it every round, and the proliferation stops. Same idea as Less…
The final “The closing point” brings the discussion to “All three reasons point to the same thing: it's missing a list of "what we already have." Write that list into the project rules file so it can see it every round, and the proliferation stops. Same idea as Less…”. The useful thing to carry forward is knowing which judgments must be revisited when input, scale, or risk changes.
I turned one judgment from this article into a small experiment I could run today. Knowing what to observe next is more useful than simply remembering the conclusion.
After reading this, I first looked for the conditions behind the idea instead of copying the method into a project. That order made the later trade-offs much clearer.
When this judgment reaches real work, which constraint should be added first? I am curious which step matters most between reading and the first practical attempt.
No discussion on this article yet.