CSS de producao com Claude Code: camadas, tokens e regressao visual
Use Claude Code para organizar CSS de producao com camadas, tokens, container queries, modo escuro e testes visuais.
CSS parece um bom trabalho para Claude Code, mas em producao nao basta a tela ficar parecida com o design. Voce precisa de arquitetura CSS, tokens reutilizaveis, layout responsivo, modo escuro, acessibilidade e checagens de regressao. Este guia usa um card de preco para mostrar como deixar Claude Code trabalhar rapido sem transformar a folha de estilos em varios remendos.
Design token e uma decisao de design com nome: cor, espacamento, raio ou sombra. Cascade layers sao prateleiras de prioridade para regras CSS. Container queries mudam o componente conforme a largura do contêiner, nao apenas conforme o viewport. Quando essas definicoes aparecem no prompt, Claude Code tende a seguir melhor o sistema existente.
Use as referencias oficiais ao adaptar os exemplos: MDN @layer, CSS custom properties, container queries, prefers-color-scheme, contraste no W3C e comparacoes visuais do Playwright. Para o fluxo do Claude Code, use Claude Code common workflows. Como links internos, veja boas praticas de CLAUDE.md e estrategias de teste.
Primeiro defina o limite do trabalho
Se voce pedir apenas “organize o CSS”, Claude Code pode melhorar a tela atual e piorar a manutencao futura. Projetos reais misturam CSS global, CSS Modules, utilitarios Tailwind, estilos de Markdown, padroes do navegador e overrides antigos. Sem limite, o assistente tende a criar seletores mais fortes em vez de melhorar a estrutura.
Comece com um harness, ou seja, a moldura segura de trabalho para o agente. Informe arquivos alvo, camadas permitidas, nomes de tokens, comandos obrigatorios e areas proibidas. CSS cresce rapido porque o resultado visual aparece na hora. O harness mantem o diff revisavel.
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"]
Comece com inspecao:
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.
Esse prompt evita que Claude Code ignore as convencoes existentes. A decisao humana e o limite: qual componente muda, quais regras continuam e quais comandos provam que a alteracao esta segura.
Fixe prioridade com cascade layers
A cascata decide qual regra vence quando varias regras atingem o mesmo elemento. Aumentar especificidade, importar depois ou usar !important resolve uma entrega, mas dificulta a seguinte. @layer deixa as prioridades explicitas.
/* 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%;
}
}
Peça para Claude Code classificar antes de reescrever:
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.
O erro comum e migrar pela metade. Uma regra fora de layer ainda pode vencer uma regra dentro de layer, e @import tambem tem regra de posicao. Comece com um componente novo, valide o comportamento e depois migre CSS antigo em partes pequenas.
Guarde decisoes de design em tokens CSS
Tokens impedem que Claude Code invente um novo verde, uma nova sombra e um novo raio em cada tarefa. Na pratica, sao variaveis CSS para decisoes reutilizaveis.
/* 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);
}
}
Em producao, peça contraste, nao apenas cores bonitas. WCAG normalmente exige pelo menos 4.5:1 para texto comum. Confira texto principal, texto secundario, links, botoes e focus ring nos dois temas.
Mantenha card e botao na camada de componentes
Cards e botoes aparecem em blogs, dashboards SaaS, landing pages, configuracoes e checkout. Se Claude Code criar classes genericas como .title ou .button, outra pagina pode quebrar. Use nomes que mostrem responsabilidade.
/* 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;
}
}
Crie uma rota de preview estavel, como /style-lab, para Playwright comparar sempre o mesmo conteudo.
<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>
Separe viewport de container
Media queries respondem ao viewport. Container queries respondem ao espaco real do componente. Isso importa quando o mesmo card aparece em uma landing larga, em uma sidebar estreita e em um grid 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;
}
}
}
Nao diga apenas “deixe responsivo”. Peça checagem em 320, 375, 768, 1024 e 1440 px: overflow horizontal, quebra de texto, focus ring, altura do CTA e layout no modo escuro.
Casos de uso praticos
Caso um: card de monetizacao em blog ou landing. Anuncios, afiliados, consultoria e downloads gratuitos precisam aparecer sem layout shift nem ruido visual. Peça CSS de componente, responsivo, modo escuro e check visual no mesmo diff pequeno.
Caso dois: tela de configuracoes SaaS. Cards, formularios, acoes perigosas e estados salvos dividem a mesma superficie. Se cada pagina inventa cores, rebranding fica caro. Use somente tokens existentes e pare se faltar algum.
Caso tres: CSS legado de CMS. Markdown e MDX costumam ter regras globais para h2, table, pre e blockquote. Limite a .legacy-markdown e compare artigos publicados.
Caso quatro: inicio de um design system. Nao troque tudo de uma vez. Comece por cards e botoes, porque o diff fica pequeno e util.
Armadilhas de revisao
A primeira armadilha e !important; se parecer necessario, Claude Code deve explicar o conflito de seletores. A segunda e modo escuro sem contraste. A terceira e usar viewport para um problema de container. A quarta e teste visual instavel por fontes externas, animacoes, dados aleatorios ou anuncios ao vivo.
Regressao visual com Playwright
Nao deixe a verificacao so para o olho humano. Playwright compara o card em varios tamanhos, modo claro, modo escuro e 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
Finalize com revisao 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 e resultado pratico
Um artigo de CSS precisa de proximo passo. Desenvolvedores individuais podem usar a checklist gratuita. Times podem seguir para treinamento e consultoria Claude Code. Para regras repetiveis, leia harness engineering.
No teste pratico, o maior ganho nao veio de @layer sozinho, mas do prompt inicial de inspecao. Quando Claude Code lia estilos, tokens e comandos de validacao antes de editar, o diff ficava no card e no botao. Quando eu pedia apenas “melhore o estilo”, apareciam cores hardcoded, espacamentos duplicados e nenhum check visual.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.
Artigos relacionados
Escada de segurança de permissões no Claude Code
Amplie de read-only para edições limitadas, comandos de prova e deploy checks sem perder controle.
Claude Code Small PR Proof Pack: pequenas mudanças fáceis de revisar
Um pacote de prova para PRs do Claude Code: diff, checks, URL pública, CTA e rollback.
Gate de revisão antes do commit com Claude Code
Revisão antes do commit com Claude Code: diff, build, URL pública, Gumroad, consultoria, testes e arquivos fora do escopo.