·6 min read·

Why we still write CSS in 2025.

Tailwind is on every project. Styled-components died quietly. CSS-in-JS is mostly gone. And yet our team still writes hand-rolled CSS in places — here's why.

Tailwind is on every project we ship. Styled-components is gone. Emotion is gone. CSS-in-JS lives in a few legacy codebases and almost no new ones. And yet, in 2025, our team still writes plenty of plain CSS — sometimes more than the Tailwind. We have opinions about why.

What Tailwind is great for

  • 01Application chrome — the small, repeated, utility-flavoured patterns that make up 80% of a UI.
  • 02Working in teams. Class names are scoped to the element, conflicts are impossible, code review is easier.
  • 03Anywhere the design system is real and the tokens map cleanly onto utilities.

Where we still write CSS

  • 01Anything bespoke. Hero animations, kinetic typography, custom motion patterns — these are CSS, not utility soup.
  • 02Print stylesheets. Tailwind isn't designed for them.
  • 03Complex grid layouts that read better with named lines than utility classes.
  • 04Components with 30+ properties where the utility version becomes longer than the CSS version.

When CSS reads better than Tailwind

hero.csscss
/* Bespoke kinetic typography — much clearer as CSS than utilities */
.hero-headline {
  font-family: var(--font-display);
  font-size: clamp(56px, 8vw, 120px);
  line-height: 0.92;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  background: linear-gradient(180deg, var(--color-on-primary) 0%, var(--color-on-primary-mute) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: headlineSlideUp 800ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

@keyframes headlineSlideUp {
  from { transform: translateY(40px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

Rules we use

  • 01Token-first, always. Whether the rule lives in Tailwind or in a CSS file, it points at the same CSS variables.
  • 02Scoped to the component. Either via <style scoped> or via a clear naming convention. No globals.
  • 03If a Tailwind class string passes 12 utilities, consider whether a CSS file would read better.
  • 04Don't @apply your way out of the problem. @apply is sugar; it can hide what's actually happening.

The argument isn't 'Tailwind vs CSS'. The argument is 'use each one where it earns its keep'. The team that does both fluently is faster than the team that's all-in on either.

The argument isn't 'Tailwind vs CSS'. The argument is 'use each one where it earns its keep'. The team that does both fluently is faster than the team that's all-in on either.

Talk to Remiam about a system like this.