Tailwind or own CSS: which approach to choose
How Tailwind and own CSS differ: twelve criteria, which approach for which project, one card built both ways with measured file sizes, six rules of order and common mistakes.
In short
Tailwind and your own CSS lead to the same result in the browser — the difference is in where the styles live and who maintains them. Tailwind puts styles into the markup as short ready-made classes: fast to start, one vocabulary for the whole team, but long class strings and a build step. Your own CSS keeps styles in separate files on a token system: clean markup, no dependency on a tool and full use of modern CSS, but it needs discipline so the files do not turn into a dump. Choose Tailwind when the project will be maintained by a team that already works with it; choose your own CSS on tokens when the design is unique and the project should not depend on a framework.
In short: which one to choose
The decisive question is not taste but who will change the styles in a year. If the project goes to an in-house team that writes in Tailwind, building it in Tailwind saves them weeks: they open the markup and see a familiar vocabulary. If the studio maintains the project or the design has to be unique, own CSS on tokens gives cleaner markup, smaller files and no dependency on the next major version of a tool.
Both approaches rest on the same foundation — design tokens. In Tailwind 4 they live in the @theme block and become CSS variables; in own CSS they are CSS variables from the start. Whoever keeps colours, spacing and fonts in one place wins with either tool.
- Your team works in Tailwind — Tailwind
- Unique design, long life — own CSS
- Either way — tokens first
Tailwind and own CSS: a detailed comparison
Twelve criteria side by side. File sizes were measured on the same card built both ways.
| Criterion | Tailwind | Own CSS |
|---|---|---|
| Where the styles live | classes in the markup | separate files by component |
| Markup | long class strings | short names by meaning |
| Start of a project | very fast, the scale is ready | tokens are set up first |
| Tokens | in @theme, become CSS variables | CSS variables from the start |
| Consistency | held by the scale | held by tokens and discipline |
| CSS for one card | 7.1 KB, 2.3 KB gzip | 0.9 KB, 0.4 KB gzip |
| Growth with the site | slow, classes are reused | with each component |
| Modern CSS | through variants: @container, has-[…] | directly, all of it |
| Build | required | optional |
| Unique design | possible, fights the scale | natural |
| A new developer | knows the vocabulary already | learns the project’s system |
| Dependence | on the tool and its versions | on the browser only |
Which approach for which project
Ten typical situations with a recommendation and the reason.
| Situation | Take | Why |
|---|---|---|
| The project goes to your team on Tailwind | Tailwind | they maintain it in their own vocabulary |
| Admin panel or internal tool | Tailwind | many standard screens, speed matters more than uniqueness |
| Prototype for a test | Tailwind | the ready scale saves days |
| Corporate site with its own style | Own CSS | the design is not built from a standard scale |
| Premium brand, a lot of motion | Own CSS | animation and details are easier to write directly |
| Site without a build step | Own CSS | Tailwind needs a build |
| Design system for several products | Own CSS on tokens | the tokens outlive any framework |
| React application | either | both work; the team decides |
| Email templates | Own CSS | mail clients need inline styles anyway |
| An existing project | what it is already in | two systems in one project are worse than either |
One card, two approaches
The same product card built in Tailwind 4 and in own CSS with the same tokens. Both builds were opened in a browser and look identical.
Tailwind: the tokens
In Tailwind 4 the settings moved from a JavaScript file into CSS.
@import "tailwindcss";
/* Project tokens: Tailwind 4 turns them into CSS variables
and into classes such as text-ink, bg-ink, border-line */
@theme {
--color-ink: #171817;
--color-muted: #5f625f;
--color-line: #e2e3e1;
}
Tailwind: the card
Every style is a class in the markup; hover and focus are variants of the same classes.
<article class="max-w-sm rounded-lg border border-line bg-white p-6">
<h3 class="text-lg font-semibold tracking-tight text-ink">Oak table</h3>
<p class="mt-2 text-sm text-muted">Solid oak, 160 × 90 cm</p>
<a href="/catalog/oak-table"
class="mt-6 inline-flex min-h-11 items-center rounded-md bg-ink px-5
text-sm font-medium text-white transition-colors hover:bg-ink/80
focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink">
Details
</a>
</article>
Own CSS: the card
The markup says what the element is; how it looks is decided in the stylesheet.
<article class="card">
<h3 class="card__title">Oak table</h3>
<p class="card__text">Solid oak, 160 × 90 cm</p>
<a class="card__link" href="/catalog/oak-table">Details</a>
</article>
Own CSS: tokens and the component
The same tokens as CSS variables and one component. Minified, it is 0.9 KB — Tailwind’s file for this card is 7.1 KB, about half of it the style reset.
/* Project tokens: colours, spacing and radii in one place */
:root {
--color-ink: #171817;
--color-muted: #5f625f;
--color-line: #e2e3e1;
--space-2: 0.5rem;
--space-6: 1.5rem;
--radius: 0.5rem;
}
/* The component: class names say what it is, not how it looks */
.card {
box-sizing: border-box;
max-width: 24rem;
padding: var(--space-6);
border: 1px solid var(--color-line);
border-radius: var(--radius);
background: #fff;
}
.card__title {
margin: 0;
font-size: 1.125rem;
font-weight: 600;
letter-spacing: -0.025em;
color: var(--color-ink);
}
.card__text {
margin: var(--space-2) 0 0;
font-size: 0.875rem;
color: var(--color-muted);
}
.card__link {
display: inline-flex;
align-items: center;
min-height: 2.75rem;
margin-top: var(--space-6);
padding: 0 1.25rem;
border-radius: 0.375rem;
background: var(--color-ink);
color: #fff;
font-size: 0.875rem;
font-weight: 500;
text-decoration: none;
transition: background-color 0.15s;
}
.card__link:hover {
background: color-mix(in oklab, var(--color-ink) 80%, transparent);
}
.card__link:focus-visible {
outline: 2px solid var(--color-ink);
outline-offset: 2px;
}
How to keep either approach clean
Both approaches degrade the same way — through exceptions. Six rules that stop it.
-
01
Tokens first
Colours, spacing, radii and fonts are set before the first component, in one place.
-
02
Components in templates
In Tailwind a repeated card is a template or a component, not a copied string of classes.
-
03
Few arbitrary values
Every
p-[13px]breaks the scale; a missing step is added to the tokens. -
04
@apply sparingly
Rebuilding classic CSS out of
@applygets the costs of both approaches and the benefits of neither. -
05
Names by meaning
In own CSS
.card__title, not.bold-black-text— the look will change, the meaning will not. -
06
Layers instead of !important
@layersets the order of resets, components and exceptions, so specificity wars do not start.
Common mistakes when choosing
-
Tailwind as a design
The default scale without own tokens makes the site look like thousands of others.
-
Own CSS without a system
Values in every rule instead of tokens — in a year nobody knows which grey is right.
-
Two systems in one project
Half in utilities, half in own files — every change has to be searched for in both.
-
Choosing for the size
A few kilobytes of CSS rarely decide speed — images, fonts and scripts weigh far more.
-
Classes built from strings
Tailwind finds only whole class names in the code;
bg-${color}silently disappears from the build. -
Forgetting the next major version
Moving from Tailwind 3 to 4 changed the configuration — a framework needs updating time in the plan.
Questions about Tailwind and own CSS
Is Tailwind better than plain CSS?
Neither is better: Tailwind is faster to start and easier to hand to a team, own CSS gives cleaner markup and no dependency.
Does Tailwind slow the site down?
No: the build keeps only the classes in use, and on a large site the file stays small.
What changed in Tailwind 4?
The settings moved into CSS (@theme), tokens became CSS variables, and the build got much faster.
Is it hard to move from Tailwind to own CSS?
It means rewriting the markup of every component — so the choice is made at the start.
Does the choice affect SEO?
No: search engines and AI assistants read the HTML structure and the text, not the class names.
Can Tailwind use container queries?
Yes, since version 4 they are built in: @container on the parent and @md: on the children.
What about Bootstrap?
It gives ready components with a recognisable look — suitable for internal tools, rarely for a site with its own style.
Online form
Discuss
the layout
I build on my own token system, and use Tailwind when the project will be maintained by your team and they work with it. Tell me about the project — I answer within one working day.