CSS Modules & Vanilla Extract mit Claude Code: Scoped Styles 2026
CSS Modules und Vanilla Extract lösen das globale CSS-Problem ohne Runtime-Overhead. Claude Code kennt beide Ansätze: Scoped CSS mit automatischen Klassen-Hashes, Theming mit CSS Custom Properties und Vanilla Extract als Zero-Runtime CSS-in-TypeScript.
CSS-Lösungen im Vergleich
| Ansatz | Runtime JS | TypeScript | Theming | Ideal für |
|---|---|---|---|---|
| CSS Modules | 0kb | Via d.ts | CSS Variables | Klassisches Scoping |
| Vanilla Extract | 0kb | Native | createTheme() | Design Systems |
| Tailwind CSS | 0kb | Via Plugin | theme.extend | Utility-first |
| styled-components | ~15kb | Gut | ThemeProvider | Component-first |
| Emotion | ~8kb | Gut | ThemeProvider | Flexibel |
CSS Modules: Scoped Styles ohne Config
CSS ModulesAutomatisch gescopte Klassennamen
/* Button.module.css */
/* Prompt: "Erstelle eine Button-Komponente mit CSS Modules" */
.button {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 10px 20px;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
border: none;
transition: all 0.2s ease;
}
.primary {
background: var(--color-primary);
color: white;
}
.primary:hover {
background: var(--color-primary-dark);
transform: translateY(-1px);
}
.secondary {
background: transparent;
border: 2px solid var(--color-primary);
color: var(--color-primary);
}
.small { padding: 6px 14px; font-size: 0.875rem; }
.large { padding: 14px 28px; font-size: 1.1rem; }
.loading {
opacity: 0.7;
cursor: not-allowed;
}
/* Composing (Vererbung): */
.dangerButton {
composes: button;
background: #ef4444;
color: white;
}
// Button.tsx — CSS Modules in React
import styles from './Button.module.css';
// TypeScript erkennt styles.primary, styles.secondary etc.!
type ButtonProps = {
variant?: 'primary' | 'secondary' | 'danger';
size?: 'small' | 'medium' | 'large';
loading?: boolean;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;
export function Button({ variant = 'primary', size = 'medium', loading, className, ...props }: ButtonProps) {
const classes = [
styles.button,
styles[variant],
size !== 'medium' && styles[size],
loading && styles.loading,
className,
].filter(Boolean).join(' ');
return <button className={classes} disabled={loading} {...props} />;
}
// Generiertes HTML:
// <button class="Button_button__x3k9d Button_primary__2mn4f">
// Klassen sind automatisch unique — kein Konflikt möglich!
TypeScript-Typen für CSS Modules
# tsconfig.json — CSS Modules Typen aktivieren:
{
"compilerOptions": {
"plugins": [{ "name": "typescript-plugin-css-modules" }]
}
}
# Alternativ: global.d.ts (ohne Plugin):
declare module '*.module.css' {
const styles: { [className: string]: string };
export default styles;
}
# Beste Lösung: typed-css-modules für exakte Typen:
npx typed-css-modules run 'src/**/*.module.css'
# → Generiert Button.module.css.d.ts mit exakten Klassen-Namen
Vanilla Extract: CSS-in-TypeScript
Vanilla ExtractZero-Runtime CSS-in-TypeScript
// styles.css.ts — Vanilla Extract
// Prompt: "Design System mit Vanilla Extract und Token-basiertem Theming"
import { style, styleVariants, createVar } from '@vanilla-extract/css';
// CSS Custom Property als Variable:
export const colorPrimary = createVar();
// Base Style:
export const button = style({
display: 'inline-flex',
alignItems: 'center',
padding: '10px 20px',
borderRadius: '8px',
fontWeight: 600,
cursor: 'pointer',
border: 'none',
transition: 'all 0.2s ease',
});
// Varianten automatisch generieren:
export const buttonVariant = styleVariants({
primary: {
background: '#6366f1',
color: 'white',
':hover': { background: '#4f46e5' },
},
secondary: {
background: 'transparent',
border: '2px solid #6366f1',
color: '#6366f1',
},
danger: {
background: '#ef4444',
color: 'white',
},
});
Vanilla Extract Theming: createTheme
ThemingLight/Dark Theme mit Type Safety
// theme.css.ts
import { createTheme, createThemeContract } from '@vanilla-extract/css';
// Contract definiert die "Shape" — beide Themes MÜSSEN alle Keys implementieren:
export const themeVars = createThemeContract({
colors: {
background: null,
foreground: null,
primary: null,
primaryForeground: null,
muted: null,
border: null,
},
space: { xs: null, sm: null, md: null, lg: null, xl: null },
fontSizes: { sm: null, base: null, lg: null, xl: null },
radii: { sm: null, md: null, lg: null, full: null },
});
// Light Theme:
export const lightTheme = createTheme(themeVars, {
colors: {
background: '#ffffff',
foreground: '#0f172a',
primary: '#6366f1',
primaryForeground: '#ffffff',
muted: '#f1f5f9',
border: '#e2e8f0',
},
space: { xs: '4px', sm: '8px', md: '16px', lg: '24px', xl: '32px' },
fontSizes: { sm: '0.875rem', base: '1rem', lg: '1.125rem', xl: '1.25rem' },
radii: { sm: '4px', md: '8px', lg: '12px', full: '9999px' },
});
// Dark Theme — TypeScript zwingt zur Vollständigkeit!
export const darkTheme = createTheme(themeVars, {
colors: {
background: '#0f172a',
foreground: '#f8fafc',
primary: '#818cf8',
primaryForeground: '#1e1b4b',
muted: '#1e293b',
border: '#334155',
},
space: { xs: '4px', sm: '8px', md: '16px', lg: '24px', xl: '32px' },
fontSizes: { sm: '0.875rem', base: '1rem', lg: '1.125rem', xl: '1.25rem' },
radii: { sm: '4px', md: '8px', lg: '12px', full: '9999px' },
});
// Nutzung:
// <div className={isDark ? darkTheme : lightTheme}> → CSS Variables gesetzt!
Vanilla Extract Build-Step: Styles werden zur Build-Zeit zu normalem CSS kompiliert — kein JavaScript zur Laufzeit. Bundle-Size-Auswirkung: 0 Bytes. Perfect für Server Components und statische Sites.
Styling-Modul im Kurs
Im Claude Code Mastery Kurs: vollständiges Styling-Modul mit CSS Modules, Vanilla Extract Design Systems, Sprinkles Utility API und Tailwind CSS — inkl. Migration von styled-components und Theme-Switching.
14 Tage kostenlos testen →