Produktionsreifes CSS mit Claude Code: Layer, Tokens und visuelle Tests
Mit Claude Code CSS fur Produktion strukturieren: Layer, Tokens, Container Queries, Dark Mode, A11y und visuelle Tests.
CSS wirkt wie ein einfacher Bereich fur Claude Code, aber produktionsreifes Styling ist mehr als ein ahnlicher Screenshot. Du brauchst eine CSS-Architektur, wiederverwendbare Tokens, responsive Regeln, Dark Mode, Barrierefreiheit und Regressionstests. Diese Anleitung nutzt eine Pricing Card als Beispiel und zeigt, wie Claude Code schnell arbeiten kann, ohne das Stylesheet mit Einzelkorrekturen zu fullen.
Design Tokens sind benannte Designentscheidungen fur Farbe, Abstand, Radius und Schatten. Cascade Layers sind Prioritatsregale fur CSS-Regeln. Container Queries reagieren auf den Platz eines Containers und nicht nur auf die Breite des Viewports. Wenn diese Begriffe im Prompt einfach erklart werden, folgt Claude Code dem vorhandenen System deutlich besser.
Halte die offiziellen Referenzen bereit: MDN @layer, CSS Custom Properties, Container Queries, prefers-color-scheme, W3C Contrast Guidance und Playwright Visual Comparisons. Fur Claude Code nutze Claude Code common workflows. Intern passen CLAUDE.md Best Practices und Testing Strategies dazu.
Erst den Arbeitsrahmen setzen
Wenn du nur “raume das CSS auf” schreibst, kann Claude Code den aktuellen Screen verbessern und die Wartung verschlechtern. Echte Projekte mischen globales CSS, CSS Modules, Tailwind Utilities, Markdown-Styles, Browser-Defaults und alte Overrides. Ohne Grenze fugt der Assistent oft starkere Selektoren hinzu, statt die Struktur zu verbessern.
Baue zuerst einen Harness, also den sicheren Arbeitsrahmen fur den Agenten. Nenne Ziel-Dateien, erlaubte Layer, Token-Namen, Pflichtbefehle und verbotene Bereiche. CSS-Anderungen wachsen schnell, weil das visuelle Ergebnis sofort sichtbar ist. Der Rahmen halt den Diff reviewbar.
flowchart LR
P["Claude Code Prompt"] --> 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"]
Starte mit Inspektion statt Editieren:
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.
Dieser Prompt verhindert, dass Claude Code ein paralleles Styling-System einfuhrt. Die menschliche Entscheidung ist die Grenze: welche Komponente sich andert, welche Regeln gelten und welche Befehle den Erfolg beweisen.
Prioritat mit Cascade Layers fixieren
Die Cascade entscheidet, welche Regel gewinnt, wenn mehrere Regeln auf dasselbe Element passen. Mehr Spezifitat, spatere Imports oder !important losen kurzfristig Konflikte, machen aber die nachste Anderung teurer. @layer macht die Prioritaten sichtbar.
/* 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%;
}
}
Lass Claude Code zuerst klassifizieren:
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.
Der typische Fehler ist eine halbe Migration. Unlayered Rules konnen Layer-Regeln weiterhin uberstimmen, und @import hat eigene Platzierungsregeln. Beginne mit einer neuen Komponente, prufe das Verhalten und migriere alten CSS-Code in kleinen Schritten.
Designentscheidungen als CSS Tokens speichern
Tokens verhindern, dass Claude Code bei jeder Aufgabe ein neues Grun, einen neuen Schatten und einen neuen Radius erfindet. Praktisch sind es CSS-Variablen fur wiederverwendbare Entscheidungen.
/* 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);
}
}
In Produktion geht es nicht nur um schone Farben. Frage nach Kontrast. WCAG erwartet fur normalen Text meist mindestens 4.5:1. Body Text, muted Text, Links, Buttons und Focus Ring mussen in hellen und dunklen Themes funktionieren.
Card und Button in der Komponenten-Schicht halten
Cards und Buttons tauchen in Blogs, SaaS-Dashboards, Landing Pages und Einstellungen immer wieder auf. Wenn Claude Code generische Klassen wie .title oder .button erganzt, bricht irgendwann eine andere Seite. Nutze Namen mit klarer Verantwortung.
/* 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;
}
}
Lege eine stabile Preview Route wie /style-lab an, damit Playwright deterministischen Inhalt vergleicht.
<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 Regeln und Container Queries trennen
Media Queries reagieren auf den Viewport. Container Queries reagieren auf den Platz der Komponente. Das ist wichtig, wenn dieselbe Card auf einer breiten Landing Page, in einer schmalen Sidebar und in einem Dashboard Grid lebt.
/* 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;
}
}
}
Schreibe nicht nur “mach es responsive”. Nenne 320, 375, 768, 1024 und 1440 px und bitte um Checks fur horizontalen Overflow, Umbruche, Focus-Ring-Clipping, CTA-Hohe und Dark Mode.
Praktische Use Cases
Use Case eins ist eine Monetarisierungs-Card fur Blog oder Landing Page. Ads, Affiliate Links, Beratung und kostenlose Downloads mussen sichtbar sein, ohne Layout Shift und visuelles Rauschen zu erzeugen. Bitte Claude Code um Komponenten-CSS, Responsive-Verhalten, Dark Mode und visuelle Checks in einem kleinen Diff.
Use Case zwei ist ein SaaS Settings Screen. Cards, Formulare, destruktive Aktionen und Save States teilen dieselbe Flache. Wenn jede Seite Farben erfindet, wird ein Rebranding teuer. Erlaube nur vorhandene Tokens und stoppe, wenn ein neuer Token fehlt.
Use Case drei ist Legacy-CSS fur CMS-Inhalte. Markdown und MDX haben oft globale Regeln fur h2, table, pre und blockquote. Begrenze Anderungen auf .legacy-markdown und vergleiche veroffentlichte Seiten per Screenshot.
Use Case vier ist der Einstieg in ein Design System. Migriere nicht alles auf einmal. Cards und Buttons sind gute erste Ziele, weil der Diff klein bleibt und der Nutzen sofort sichtbar ist.
Fehler, die im Review auffallen mussen
Der erste Fehler ist !important. Wenn Claude Code meint, es sei notig, soll es den Selektor-Konflikt erklaren. Der zweite ist Dark Mode ohne Kontrastprufung. Der dritte ist Viewport-Denken, obwohl das Problem am Container hangt. Der vierte ist ein wackeliger Screenshot-Test durch externe Fonts, Animationen, Zufallsdaten oder Live Ads.
Visuelle Regression mit Playwright
CSS sollte nicht nur mit menschlichen Augen gepruft werden. Playwright kann die Card in mehreren Breiten, im hellen Theme, im dunklen Theme und mit sichtbarem Tastaturfokus vergleichen.
// 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
Schliesse mit einem festen Review-Prompt:
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 und Praxisergebnis
Ein CSS-Artikel braucht einen nachsten Schritt. Einzelne Entwickler konnen mit der kostenlosen Checkliste starten. Teams gehen sinnvoll zu Claude Code Training und Beratung. Fur wiederholbare Regeln passt Harness Engineering.
Im Test brachte nicht @layer allein den grossten Gewinn, sondern der Inspektions-Prompt am Anfang. Wenn Claude Code zuerst bestehende Styles, Tokens und Validierungsbefehle las, blieb der Diff auf Card und Button beschrankt. Bei “mach das Styling besser” entstanden dagegen hardcodierte Farben, doppelte Abstände und keine visuellen Checks.
Kostenloses PDF: Claude-Code-Cheatsheet
E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.
Wir schützen Ihre Daten und senden keinen Spam.
Über den Autor
Masa
Engineer für praktische Claude-Code-Workflows und Team-Einführung.
Ähnliche Artikel
Claude Code Permission Safety Ladder: Zugriff kontrolliert erweitern
Von read-only zu begrenzten Änderungen, Prüfbefehlen und Deploy-Checks mit klarer Kontrolle.
Claude Code Small PR Proof Pack: kleine Änderungen reviewbar machen
Ein Proof Pack für Claude-Code-PRs: Diff, Checks, öffentliche URL, CTA-Pfad und Rollback.
Claude-Code-Review-Gate vor dem Commit
Vor dem Commit mit Claude Code prüfen: Diff, Build, öffentliche URL, Gumroad-Links, Beratung-CTA, fehlende Tests und fremde Dateien.