Tips & Tricks (Actualizado: 2/6/2026)

CSS de produccion con Claude Code: capas, tokens y regresion visual

Usa Claude Code para ordenar CSS de produccion con capas, tokens, container queries, modo oscuro y checks visuales.

CSS de produccion con Claude Code: capas, tokens y regresion visual

CSS parece una tarea facil para Claude Code, pero en produccion no basta con que la pantalla se parezca al diseno. Necesitas arquitectura CSS, tokens reutilizables, layout responsive, modo oscuro, accesibilidad y pruebas de regresion. Esta guia usa una tarjeta de precios para mostrar como dejar que Claude Code avance rapido sin llenar la hoja de estilos de parches sueltos.

Un design token es una decision de diseno con nombre: color, espacio, radio o sombra. Las cascade layers son estantes de prioridad para las reglas CSS. Las container queries cambian el componente segun el ancho de su contenedor, no solo segun el viewport. Cuando estas definiciones aparecen en el prompt, Claude Code entiende mejor el sistema existente.

Consulta las referencias oficiales al adaptar los ejemplos: MDN @layer, CSS custom properties, container queries, prefers-color-scheme, contraste en W3C y comparaciones visuales de Playwright. Para el flujo de Claude Code, parte de Claude Code common workflows. Como enlaces internos, revisa buenas practicas de CLAUDE.md y estrategias de testing.

Primero crea el marco de trabajo

Si pides “mejora el CSS”, Claude Code puede arreglar la vista actual y complicar el mantenimiento futuro. Un proyecto real mezcla CSS global, CSS Modules, utilidades de Tailwind, estilos de Markdown, valores por defecto del navegador y overrides antiguos. Sin limites, el asistente suele anadir selectores mas fuertes en lugar de mejorar la estructura.

El primer paso es definir un harness, es decir, el marco seguro de trabajo para el agente. Indica los archivos objetivo, las capas que puede tocar, la nomenclatura de tokens, los comandos obligatorios y las zonas prohibidas. En CSS el resultado visual anima a seguir cambiando, por eso el marco mantiene el diff revisable.

flowchart LR
  P["Prompt para Claude Code"] --> L["cascade layers"]
  L --> T["design tokens"]
  T --> C["card/button components"]
  C --> R["responsive + container queries"]
  R --> D["dark mode"]
  D --> A["accessibility checks"]
  A --> V["Playwright visual regression"]

Empieza con inspeccion, no con edicion:

Read AGENTS.md, CLAUDE.md, package.json, and every file under src/styles.
Do not edit yet.
Report the current CSS architecture, naming conventions, token usage,
dark-mode strategy, responsive breakpoints, and test commands.
Then propose the smallest safe plan for a pricing card and CTA button.

Este prompt evita que Claude Code cree un sistema paralelo. La decision humana es el limite: que componente cambia, que reglas se respetan y que comandos validan la salida.

Fija la prioridad con cascade layers

La cascada decide que regla gana cuando varias reglas coinciden. Si el equipo resuelve conflictos con mas especificidad, imports posteriores o !important, la siguiente modificacion sera mas dificil. @layer permite nombrar esas prioridades.

/* src/styles/app.css */
@layer reset, tokens, base, components, utilities, overrides;

@import "./tokens.css" layer(tokens);
@import "./base.css" layer(base);
@import "./components.css" layer(components);
@import "./utilities.css" layer(utilities);

@layer reset {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }

  body,
  h1,
  h2,
  h3,
  p {
    margin: 0;
  }
}

@layer overrides {
  .legacy-markdown :where(table, pre) {
    max-width: 100%;
  }
}

Pide a Claude Code que clasifique antes de reescribir:

Move existing global CSS into the layer model in src/styles/app.css.
Do not change class names used by templates.
Use reset, tokens, base, components, utilities, and overrides only.
If a rule must go into overrides, explain why in the final response.
Run npm test and the visual check command after editing.

El error comun es migrar a medias. Una regla normal fuera de layer puede ganar a una regla dentro de layer, y @import tambien tiene reglas de posicion. Empieza con un componente nuevo, verifica el comportamiento y migra el CSS viejo por partes.

Guarda decisiones de diseno como tokens

Los tokens evitan que Claude Code invente un verde, una sombra y un radio nuevos en cada cambio. En terminos practicos, son variables CSS para decisiones que el equipo quiere reutilizar.

/* src/styles/tokens.css */
@layer tokens {
  :root {
    color-scheme: light;
    --color-bg: #f7f7f2;
    --color-surface: #ffffff;
    --color-text: #1f2933;
    --color-muted: #5d6673;
    --color-border: #d9ded7;
    --color-accent: #0f766e;
    --color-accent-strong: #0b4f49;
    --color-focus: #b45309;

    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-6: 1.5rem;
    --space-8: 2rem;

    --radius-sm: 0.25rem;
    --radius-md: 0.5rem;
    --shadow-card: 0 0.75rem 2rem rgb(31 41 51 / 0.12);
  }

  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      color-scheme: dark;
      --color-bg: #111827;
      --color-surface: #1f2937;
      --color-text: #f9fafb;
      --color-muted: #cbd5e1;
      --color-border: #475569;
      --color-accent: #2dd4bf;
      --color-accent-strong: #99f6e4;
      --color-focus: #fbbf24;
      --shadow-card: 0 0.75rem 2rem rgb(0 0 0 / 0.32);
    }
  }

  :root[data-theme="dark"] {
    color-scheme: dark;
    --color-bg: #111827;
    --color-surface: #1f2937;
    --color-text: #f9fafb;
    --color-muted: #cbd5e1;
    --color-border: #475569;
    --color-accent: #2dd4bf;
    --color-accent-strong: #99f6e4;
    --color-focus: #fbbf24;
    --shadow-card: 0 0.75rem 2rem rgb(0 0 0 / 0.32);
  }
}

En produccion, pide contraste, no solo colores bonitos. WCAG suele exigir 4.5:1 para texto normal. Revisa texto principal, texto secundario, enlaces, botones y focus ring en ambos temas.

Encierra tarjetas y botones en la capa de componentes

Las tarjetas y botones aparecen en blogs, dashboards SaaS, landing pages y pantallas de configuracion. Si Claude Code crea clases genericas como .title o .button, tarde o temprano romperan otra pagina. Usa nombres con propietario claro.

/* src/styles/components.css */
@layer components {
  .ui-card {
    container: card / inline-size;
    display: grid;
    gap: var(--space-4);
    padding: var(--space-6);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text);
    box-shadow: var(--shadow-card);
  }

  .ui-card__eyebrow {
    color: var(--color-accent);
    font-size: 0.875rem;
    font-weight: 700;
  }

  .ui-card__title {
    max-width: 18ch;
    font-size: clamp(1.5rem, 1rem + 2cqi, 2.25rem);
    line-height: 1.1;
  }

  .ui-card__body {
    color: var(--color-muted);
    font-size: 1rem;
    line-height: 1.7;
  }

  .ui-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: center;
  }

  .ui-button {
    display: inline-flex;
    min-height: 2.75rem;
    align-items: center;
    justify-content: center;
    padding: 0.75rem 1rem;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: var(--color-accent);
    color: var(--color-surface);
    font: inherit;
    font-weight: 700;
    text-decoration: none;
  }

  .ui-button:hover {
    background: var(--color-accent-strong);
  }

  .ui-button:focus-visible {
    outline: 3px solid var(--color-focus);
    outline-offset: 3px;
  }

  .ui-button[aria-disabled="true"],
  .ui-button:disabled {
    cursor: not-allowed;
    opacity: 0.55;
  }
}

Anade una ruta estable de previsualizacion, por ejemplo /style-lab, para que Playwright tenga contenido determinista.

<main class="style-lab">
  <article class="ui-card" data-testid="pricing-card">
    <p class="ui-card__eyebrow">Team plan</p>
    <h1 class="ui-card__title">Ship production CSS with Claude Code</h1>
    <p class="ui-card__body">
      Layer your CSS, reuse tokens, check dark mode, and catch visual regressions before release.
    </p>
    <div class="ui-actions">
      <a class="ui-button" href="/training/">Start with training</a>
      <a class="ui-button" href="/thanks/">Get the free checklist</a>
    </div>
  </article>
</main>

Responsive y container queries

Las media queries responden al viewport. Las container queries responden al espacio real del componente. La diferencia importa cuando la misma tarjeta vive en una landing ancha, una barra lateral estrecha y una cuadricula de dashboard.

/* src/styles/responsive.css */
@layer components {
  .style-lab {
    display: grid;
    min-height: 100svh;
    place-items: center;
    padding: clamp(1rem, 4vw, 4rem);
    background: var(--color-bg);
  }

  .pricing-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
    gap: var(--space-6);
    width: min(100%, 72rem);
  }

  @container card (min-width: 36rem) {
    .ui-card {
      grid-template-columns: 1fr auto;
      align-items: center;
    }

    .ui-card__body {
      max-width: 58ch;
    }

    .ui-actions {
      justify-content: end;
    }
  }

  @media (max-width: 40rem) {
    .ui-card {
      padding: var(--space-4);
    }

    .ui-actions,
    .ui-button {
      width: 100%;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      scroll-behavior: auto !important;
      transition-duration: 0.001ms !important;
      animation-duration: 0.001ms !important;
      animation-iteration-count: 1 !important;
    }
  }
}

No escribas solo “hazlo responsive”. Pide comprobar 320, 375, 768, 1024 y 1440 px: overflow horizontal, saltos de linea, focus ring, altura de CTA y modo oscuro.

Casos de uso reales

Caso uno: una tarjeta de monetizacion en un blog o landing. Anuncios, afiliados, consultoria y descargas gratuitas deben verse sin generar layout shift ni ruido visual. Pide CSS de componente, responsive, dark mode y check visual en el mismo cambio pequeno.

Caso dos: una pantalla de configuracion SaaS. Tarjetas, formularios, acciones peligrosas y estados guardados comparten superficie. Si cada pagina inventa colores, el cambio de marca se vuelve caro. Limita a Claude Code a tokens existentes y que se detenga si falta uno.

Caso tres: CSS legado de contenido CMS. Markdown y MDX suelen tener reglas globales para h2, table, pre y blockquote. No hagas reemplazos masivos; limita el cambio a .legacy-markdown y compara articulos publicados.

Caso cuatro: inicio de un sistema de diseno. No migres todo a la vez. Empieza por tarjetas y botones, porque se repiten mucho y el diff pequeno se revisa mejor.

Trampas que debes revisar

La primera trampa es !important. Si Claude Code cree que lo necesita, debe explicar el conflicto de selectores. La segunda es modo oscuro sin contraste: texto, enlaces, botones, bordes y focus ring deben funcionar juntos. La tercera es usar solo viewport cuando el problema depende del contenedor. La cuarta es una prueba visual inestable por fuentes externas, animaciones, datos aleatorios o anuncios vivos.

Regresion visual con Playwright

No confies todo a la revision visual manual. Playwright permite verificar la tarjeta en varios anchos, modo claro, modo oscuro y foco de teclado.

// tests/visual/style-regression.spec.ts
import { expect, test } from "@playwright/test";

const viewports = [
  { name: "mobile", width: 375, height: 812 },
  { name: "tablet", width: 768, height: 1024 },
  { name: "desktop", width: 1440, height: 900 },
];

for (const viewport of viewports) {
  test(`pricing card visual regression ${viewport.name}`, async ({ page }) => {
    await page.setViewportSize({ width: viewport.width, height: viewport.height });
    await page.emulateMedia({ colorScheme: "light", reducedMotion: "reduce" });
    await page.goto("/style-lab");

    const card = page.getByTestId("pricing-card").first();
    await expect(card).toBeVisible();
    await expect(card).toHaveScreenshot(`pricing-card-${viewport.name}-light.png`, {
      animations: "disabled",
      maxDiffPixelRatio: 0.02,
    });
  });
}

test("dark theme keeps focus states visible", async ({ page }) => {
  await page.emulateMedia({ colorScheme: "dark", reducedMotion: "reduce" });
  await page.goto("/style-lab");
  await page.locator("html").evaluate((element) => {
    element.setAttribute("data-theme", "dark");
  });

  const startButton = page.getByRole("link", { name: /start with training/i });
  await startButton.focus();
  await expect(startButton).toBeFocused();
  await expect(page.getByTestId("pricing-card").first()).toHaveScreenshot(
    "pricing-card-dark-focus.png",
    {
      animations: "disabled",
      maxDiffPixelRatio: 0.02,
    },
  );
});
npx playwright test tests/visual/style-regression.spec.ts --update-snapshots
npx playwright test tests/visual/style-regression.spec.ts

Termina con una revision critica:

Critically review the CSS diff.
Check cascade layers, token usage, selector specificity, dark mode,
container queries, keyboard focus, color contrast, reduced motion,
and Playwright visual coverage.
Return only concrete issues with file paths and line numbers.

CTA y resultado practico

Un articulo de CSS debe dar un siguiente paso claro. Para desarrolladores individuales, enlaza la checklist gratuita. Para equipos, el siguiente paso natural es formacion y consultoria de Claude Code. Si necesitas reglas repetibles, lee harness engineering.

Al probar este flujo, la mayor mejora no vino de @layer por si solo, sino del prompt de inspeccion inicial. Cuando Claude Code leia primero estilos, tokens y comandos de validacion, el diff se quedaba en la tarjeta y el boton. Cuando solo pedia “mejora el estilo”, aparecian colores hardcodeados, espacios duplicados y ningun check visual.

#Claude Code #CSS #arquitectura CSS #design tokens #frontend
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.