CategoryCode and architecture
Pure CSS or utility framework: where the rule lives
The cost of a utility framework isn’t in bytes. It is in the decisions you keep making, because the value of each rule lives in the markup you write. Native CSS with tokens puts the rule in one place and gives it a name. The choice comes down to whether your team needs an imposed rule or freedom with discipline.
Where the style rule lives on each path
On the utility path the rule lives in the class list of the element. A button carries px-4 py-2 text-sm bg-blue-600 in its own markup. The stylesheet is generated output, so the markup is the source of truth.
Tailwind’s documentation describes that mechanism. The tool treats the source files as plain text and looks for tokens that could be classes. It then generates CSS for the tokens it recognizes and discards the rest.
On the native path the rule lives in a stylesheet, selected by a class or an element. The markup names intent and the stylesheet holds the value.
That difference decides what happens when you delete a screen. On the utility path the rule disappears with the markup. On the native path the rule stays in the file, unread and still parsed.
Who decides the visual value
On the utility path whoever writes the markup decides. Two screens can ship two different paddings, and nothing in the tool stops it.
On the token path the value lives in a custom property. MDN describes custom properties as a way to define a value in one place and reference it in many. The same page names the problem they remove, which is a color duplicated in many rules and a search and replace every time it changes.
A token file sets --space-4 once. A component reads var(--space-4). The decision moves from the element to the scale.
That is the core difference: one path decides element by element, the other decides at the token.
What changes when the design changes
A rebrand on the utility path means editing markup. The brand color lives in class names, so every file that uses it has to change. A configured scale helps only when the change follows the scale.
A rebrand on the token path means editing one custom property. Every component that reads it follows, without touching a component file.
The same MDN page records one limit worth knowing. The var() function works in property values only, so it can’t be used inside a media query or a container query.
Two native features cover the rest. Cascade layers decide which set of rules wins without raising specificity. MDN’s page on layer states that the first declared layer gets the lowest priority and the last gets the highest. The same page states that normal declarations outside a layer override normal declarations inside one, and that important declarations reverse that order.
Container queries style an element by the size of its container, and MDN presents them as an alternative to media queries. A card can adapt inside a narrow sidebar without a viewport breakpoint.
What happens when someone new joins the team
On the utility path the new hire reads the markup and sees the values. The convention is enforced by the build, because Tailwind’s docs warn that class names built by string concatenation aren’t detected. Complete class names become a rule the tool checks.
On the token path the new hire reads the stylesheet and the token file. The convention is enforced by review, and nothing blocks a stray padding: 13px.
Here the shape of the team matters more than taste. A large team with rotation gets the rule for free on the utility path, and that demand is the consistency heuristic. Nielsen Norman Group states it as one of its ten: users shouldn’t have to wonder whether two screens mean the same thing.
A small team with one owner of the design system gets the rule from the token file.
What each path charges in maintenance
The utility path charges in markup verbosity, in rework when the scale changes, and in a build step. Its documented gain is size. Tailwind states that generating CSS from the classes in use keeps the stylesheet as small as possible.
The token path charges in naming and in pruning. MDN’s performance page states that all styles get parsed, whether or not layout and painting use them. The same page states that complex selectors increase file size and parsing time, and that CSS is render blocking until the browser decides it needs it.
Unused rules nobody deletes stay on that critical path. That is the bill a stylesheet that only grows keeps paying.
The middle path charges one extra decision per component, and I cover it below.
When the utility framework wins
The utility framework wins in four situations, and they are common enough to name.
- A large team with high rotation, where the rule can’t depend on who wrote the file.
- Many similar screens assembled from the same small set of components.
- A short deadline, where a naming convention is a cost the team can’t pay now.
- A product whose design changes rarely, so the scale stays stable.
What you save is decisions, not bytes. The framework fixes the values available, and the person writing markup picks one. That is a real saving when twenty people touch the same interface.
This saving has a price. You pay it in markup that hides the value, and in a stylesheet you can’t read as a design document.
The middle path: native CSS with tokens and layers
Most comparisons stop at two options. The third one is a stylesheet organized by token and by layer.
The token file holds the scales: color, space, type, radius and shadow. Custom properties give each step a name.
In the Nielsen Norman Group definition, a design system gathers the standards that let you manage design at scale. In CSS, those standards become values in the token file, and the component reads them from there.
The layers hold the order: tokens, base, components, utilities. MDN notes that the first declared layer has the lowest priority and the last has the highest, and that the priority reverses for declarations marked important.
Container queries handle components that must adapt to their own space instead of the viewport.
The cost is a convention you own and a review that keeps it. The gain is a design change that touches one file and a markup that stays readable.
How to decide without switching every two years
Decide based on who owns the value, not on this year’s trendy framework.
- If the team can’t enforce a naming convention, take the utility framework.
- If one person owns the design system and the scales change often, take tokens.
- If the product has dozens of screens with shared state, the CSS question is secondary.
- If the site is content, both paths cost more than the pages deserve.
Then write the decision down. A rule you can point to survives a new hire and a new trend.
Switch when your team’s reality changes, not because a new conference talk came out. Team size, rotation, screen count and design velocity are the inputs. When one of them moves, revisit the choice.
Where the sources disagree
Nielsen Norman Group pulls in two directions on color. The visual hierarchy article tells designers to use bright and saturated color for important items and less-saturated color for items of lesser importance. The dashboards article forbids the same move, because people don’t perceive colors as being in an order, so color shouldn’t carry magnitude.
Both rules hold when the object differs. A page uses color to mark where to look first. A chart uses color to mark how much, and that reading needs an ordered channel. A design system that keeps one color scale for both jobs inherits the conflict.
The other two articles agree with each other. The consistency heuristic asks the same element to mean the same thing across screens. The design systems article asks the team to hold one set of standards for components and patterns. Both describe the problem a token file solves. Neither says whether the token should be a class name or a custom property.
Verify before you call it decided
- Measure the CSS bytes the page loads, and the share of it the page uses.
- Search the stylesheet for raw values that should be tokens, such as hex colors and pixel spacing.
- Change one token and count the files that change.
- Read a screen written by someone else and check whether the rule is obvious.
- Confirm the build fails when a class name is assembled by string concatenation.
- Recheck after a quarter, because the team and the product both move.
The framework doesn’t charge in bytes. It charges in the decisions you keep making. Native CSS with tokens charges in discipline someone has to keep up. Pick which of those bills your team will pay.
Sources
- MDN, Using CSS custom properties
- MDN, @layer
- MDN, CSS container queries
- MDN, CSS performance optimization
- Tailwind CSS, Detecting classes in source files
- Nielsen Norman Group, Maintain Consistency and Adhere to Standards
- Nielsen Norman Group, Design Systems 101
- Nielsen Norman Group, Visual Hierarchy in UX: Definition
- Nielsen Norman Group, Dashboards: Making Charts and Graphs Easier to Understand


