Web Design and Engineering

Por qué quitamos Tailwind de producción: un design system solo CSS

Tras años usando Tailwind junto a nuestro design system, lo retiramos de producción. Esta es la arquitectura que lo reemplazó y lo que cambió.

1 de mayo de 20268 min de lectura
Por qué quitamos Tailwind de producción: un design system solo CSS

Un design system solo CSS es una librería de componentes distribuida como CSS nativo, donde cada decisión visual vive en un token, una clase o una capa de cascada, y nada depende de un framework JavaScript ni de un lenguaje de utility-class HTML. Es lo que enviamos a producción hoy en cada proyecto Studio, tras años de mantener Tailwind en paralelo con nuestros propios componentes.

Este artículo cuenta por qué dejamos de recurrir a Tailwind, y por qué "quitar Tailwind" resultó más barato que "escalar Tailwind" una vez que el design system superó los cien consumidores. Es una opinión. También es reversible: si tu equipo es de dos personas y el producto sale en tres meses, Tailwind probablemente sea la respuesta correcta para ti. El razonamiento de abajo vale para equipos que gestionan una línea de producto o venden a clientes multi-tenant.

El problema: deuda de utility-class a escala

Tailwind vende un trato limpio. Escribes clases, el compilador hace tree-shaking de las no usadas, el bundle de producción se mantiene pequeño. La documentación cita aplicaciones típicas enviando entre 5 y 15 KB de CSS gzipped. Esa parte es exacta.

El coste oculto está en otra parte. El CSS se reduce, el HTML crece. En un caso real de la comunidad, un proyecto pasó de 45 KB a 8 KB de CSS tras migrar a Tailwind, pero el HTML creció de 120 KB a 340 KB, un aumento neto de 183 KB. Las clases tienen que vivir en algún lugar. Viven en el marcado, repetidas en cada componente, cada página, cada variante de idioma.

El segundo coste es el tiempo de lectura. Un botón con ocho estados en Tailwind se ve como sesenta utility-class interrumpidas por lógica de plantilla. Para responder a una pregunta básica (¿cómo se ve este botón en modo oscuro?) el lector escanea cada clase, decodifica los prefijos y reconstruye la cascada mentalmente. Lo medimos en code review. Las revisiones de componentes con utility-class tomaron más tiempo por línea que las revisiones de componentes BEM equivalentes, y la diferencia crece con la complejidad del componente.

El tercer coste es la portabilidad. Una vez que el código tiene 30.000 cadenas de utility-class, salir de Tailwind no es un refactor de viernes por la tarde. Es un trimestre de trabajo. El lock-in tiene un precio aunque pienses quedarte.

Por qué la solución obvia no funcionó

La solución obvia es "Tailwind más componentes": usa @apply para extraer cadenas repetidas en clases nombradas, deja las utility para casos puntuales. Lo intentamos. Se derrumba por dos motivos.

Primero, @apply reintroduce el problema de cascada que Tailwind quería eliminar. Ahora tienes una clase custom que envuelve utility-class, lo que significa que especificidad, orden de override y confusión sobre la fuente de verdad vuelven a la mesa. Has cambiado un set de decisiones de cascada por dos capas de ellas.

Segundo, el equipo se parte. La mitad escribe utility inline, la otra mitad las extrae, y el design system deja de ser un único lenguaje. Las code review se vuelven debates de estilo. El trabajo semanal de auditoría DS Ops que hacemos sobre los proyectos consumidores muestra que los proyectos mixtos Tailwind más clases-componente acumulan drift de override más rápido que cualquiera de los dos enfoques puros.

Lo que sí funciona: CSS nativo en tres capas

Nuestra arquitectura de producción tiene tres capas, todas CSS nativo, todas distribuidas a través de un único paquete npm.

Capa 1: design tokens

Alrededor de 140 custom properties cubren toda la superficie visual: color, espaciado, radios, tipografía, sombra, motion. Los tokens son cadenas planas, con namespace --ds-*, definidos una vez en :root y sobrescritos en un bloque [data-theme="dark"]. Cada componente consume tokens; nada hardcodea un valor. Migrar de una marca a otra es un swap de tokens, no una reescritura de CSS. Cubrimos los compromisos de este enfoque en design tokens vs variables CSS vs Tailwind.

Capa 2: componentes

Unos 60 componentes se distribuyen como clases CSS planas con prefijo ds-*: .ds-btn, .ds-card, .ds-input. Cada componente tiene su propio bloque en la hoja de estilos, usa tokens para cada valor y expone modificadores (.ds-btn--ghost, .ds-card--bordered) en lugar de composición de utility. Un lector que conoce los nombres de los tokens y lee ds-btn--ghost puede predecir el resultado visual sin abrir el archivo.

Capa 3: utility

Una lista corta de utility de layout y de estado (ds-flex, ds-grid, ds-hover-row, ds-focus-ring) cubre los casos en los que una regla puntual sería un desperdicio como componente entero. La lista es cerrada y auditada. No enviamos ds-text-2xl, ds-px-4 ni utility de sizing; esos valores vienen de modificadores de componente. La superficie de utility se mantiene lo bastante pequeña para que un dev la sostenga en la cabeza.

Las tres capas se cosen mediante CSS cascade layers, que hoy tienen más del 96% de soporte global. Declaramos el orden una sola vez al inicio del paquete: @layer reset, tokens, base, components, utilities;. Las guerras de especificidad dejan de existir porque el orden de capas, no el selector, decide quién gana.

El soporte de navegador es lo que cambió

Esta arquitectura habría sido dolorosa en 2022. Es directa en 2026. El nesting nativo de CSS alcanzó Baseline Widely Available en 2026, después de volverse Newly Available en agosto de 2023. Las cascade layers cruzaron el 96% de soporte. color-mix(), oklch(), las container queries y :has() se estabilizaron en la misma ventana. El CSS nativo en 2026 cubre cerca del 90% de lo que los equipos buscaban en Sass, PostCSS o Tailwind en 2020. Mapeamos toda la superficie en CSS moderno en 2026.

Si tu matriz de soporte excluye navegadores anteriores a 2024, el CSS nativo es un lenguaje completo. La mayoría de targets B2B SaaS cumplen ese suelo.

La señal del ecosistema Tailwind que no ignoramos

En enero de 2026, Tailwind Labs recortó su equipo de ingeniería de cuatro a una persona, citando una caída de tráfico de aproximadamente el 40% desde 2023 y un colapso de ingresos del 80%. El framework en sí está ampliamente usado y la v4 con el motor Oxide es genuinamente rápida. El modelo de negocio detrás (componentes de pago, tooling de pago) se erosionó cuando los asistentes de IA empezaron a servir la documentación de Tailwind directamente a los desarrolladores. No nos gustan los recortes de equipos. Sí los leemos como señal de hacia dónde van la administración y la estabilidad del roadmap.

Un design system que vive en la cadencia de releases de un vendor está expuesto a la realidad comercial del vendor. Un design system que vive en CSS nativo está expuesto solo al proceso de estándares del navegador, que se mueve despacio y de forma predecible.

Cómo se ve en la práctica

Así se lee una definición de botón en nuestro sistema, en forma compacta.

@layer components {
  .ds-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--ds-space-2);
    padding: var(--ds-space-2) var(--ds-space-4);
    border-radius: var(--ds-radius-md);
    background: var(--ds-color-bg-action);
    color: var(--ds-color-fg-on-action);
    font: var(--ds-font-body-sm);
    transition: background var(--ds-motion-fast);

    &:hover { background: var(--ds-color-bg-action-hover); }
    &[disabled] { opacity: 0.6; pointer-events: none; }
  }

  .ds-btn--ghost {
    background: transparent;
    color: var(--ds-color-fg-default);
    box-shadow: inset 0 0 0 1px var(--ds-color-border-subtle);
  }
}

Leer ese bloque te dice todo: qué variables lo dirigen, qué estados interactivos existen, qué override de modo oscuro ocurrirá automáticamente a través del swap de tokens. Sin sopa de clases en el marcado, sin runtime JavaScript, sin cadena de plugins PostCSS que depurar.

El compromiso también es visible. Escribes más CSS. La superficie del paquete crece. Necesitas gobernanza, una cadencia de auditoría y un mantenedor al que le importe. Hacemos una auditoría DS semanal sobre cada proyecto consumidor y atrapa el drift antes de que se acumule. Si tu equipo no puede sostener esa cadencia, el "it just works" de Tailwind es genuinamente más seguro.

Cómo evaluarlo para tu equipo

Tres preguntas deciden si la migración vale tu trimestre.

¿Estás enviando más de una superficie de producto? Un sitio, una app, una página marketing pueden quedarse en Tailwind para siempre y no sentir dolor. Dos productos con componentes compartidos empiezan a pagar intereses sobre cada utility-class que vive en dos árboles de marcado.

¿Tienes un diseñador que piensa en tokens? Toda la arquitectura se apoya en una lista de tokens que un diseñador mantiene junto al equipo de ingeniería. Sin eso, el enfoque solo CSS deriva otra vez hacia valores ad hoc y se pierde el beneficio de consistencia.

¿Tu matriz de soporte es flexible? Si debes soportar Safari 15 o Firefox ESR fijado a 2022, las cascade layers y el nesting nativo te pelearán. La mayoría de productos B2B y consumer modernos han superado esa línea para 2026, pero verifica antes de comprometerte.

Si dos de tres respuestas son sí, la migración se paga en dos trimestres. Si solo una es sí, quédate en Tailwind y revisa dentro de un año.

Lo que conservamos de Tailwind

Tres ideas sobrevivieron a la migración y viven en nuestro sistema hoy. La mentalidad de restricción (un set pequeño y fijo de espaciados y colores en lugar de números arbitrarios). El patrón modo-oscuro-como-data-attribute, más simple que un toggle de clase y más fácil de testear. La convención de utility-class para primitivas de layout, mantenida corta y cerrada. Los nombres cambiaron; la disciplina se quedó.

Quitar Tailwind no es una vuelta de honor sobre un framework que hizo su trabajo durante una década. Es reconocer que, para un estudio que vende trabajo de design system, poseer el CSS hasta la cascada es el producto, no un detalle de implementación.

Foto de Tim Schmidbauer en Unsplash

Preguntas frecuentes

How long does it take to remove Tailwind from a production codebase?
Plan one engineering quarter for a codebase of 30,000 to 50,000 utility-class instances, working alongside feature delivery. The migration is mechanical for layout and typography, slower for interactive states and dark mode, and slowest for places where Tailwind variants encoded business logic (responsive copy, conditional spacing). Run it incrementally per route or per feature flag, never as a single big bang. The cost is real; it pays back when the team stops paying interest on every new component.
Do CSS cascade layers work with Server Components in Next.js?
Yes. Cascade layers are pure CSS, processed by the browser, with zero coupling to the rendering model. We use them in production with Next.js 16 App Router and React 19 Server Components. The only nuance is that you import the design system stylesheet once in the root layout, declared at the top so the layer order is established before any route-level CSS loads.
Can you mix Tailwind and a CSS-only design system during migration?
Technically yes, practically not for long. Put Tailwind in its own cascade layer below your design system layer, so component classes always win. This buys you a migration window where new code uses the design system and existing code keeps working. Set a deadline (one quarter is realistic) and remove Tailwind entirely at the end. Long-term coexistence reintroduces the hybrid drift problem we described above.

Studio

Empieza un proyecto.

Un partner único para empresas, sector público, startups y SaaS. Producción más rápida, tecnología moderna, costes reducidos. Un equipo, una factura.