Zum Inhalt springen
React Anfänger 30 min

CSS Modules & Styled Components

Lerne CSS Modules und Styled Components kennen - zwei populäre Ansätze für komponentenbasiertes Styling ohne Namenskonflikte.

Aktualisiert:

CSS Modules & Styled Components

In groesseren React-Projekten fuehrt klassisches CSS schnell zu Namenskonflikten. CSS Modules und Styled Components loesen dieses Problem auf elegante Weise. In diesem Tutorial lernst du beide Ansaetze kennen.

CSS Modules

CSS Modules sind CSS-Dateien mit lokalem Scope. Jede Klasse wird automatisch eindeutig umbenannt, sodass keine Konflikte entstehen.

Wie es funktioniert

Erstelle eine Datei mit der Endung .module.css:

/* Button.module.css */
.button {
  padding: 10px 20px;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-size: 1rem;
  font-weight: 600;
  transition: all 0.2s;
}

.primary {
  background-color: #3498db;
  color: white;
}

.primary:hover {
  background-color: #2980b9;
}

.secondary {
  background-color: #ecf0f1;
  color: #2c3e50;
}

.secondary:hover {
  background-color: #d5dbdb;
}

.large {
  padding: 14px 28px;
  font-size: 1.125rem;
}
// Button.jsx
import styles from './Button.module.css';

function Button({ variant = 'primary', size, children, onClick }) {
  const className = [
    styles.button,
    styles[variant],
    size === 'large' && styles.large
  ].filter(Boolean).join(' ');

  return (
    <button className={className} onClick={onClick}>
      {children}
    </button>
  );
}

export default Button;

Was passiert unter der Haube?

/* Im Browser wird daraus: */
.Button_button_x7yz3 { /* ... */ }
.Button_primary_a2bc4 { /* ... */ }

Die Klassen werden automatisch umbenannt – Konflikte sind unmoeglich!

Vorteile von CSS Modules

VorteilBeschreibung
Lokaler ScopeKlassen gelten nur in der Komponente
Keine KonflikteEindeutige Klassennamen
Standard-CSSKeine neue Syntax zu lernen
Vite-SupportFunktioniert out of the box
IDE-SupportAutovervollstaendigung moeglich

Komplexeres Beispiel: Card-Komponente

/* Card.module.css */
.card {
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: transform 0.2s, box-shadow 0.2s;
}

.card:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}

.image {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.content {
  padding: 1.25rem;
}

.title {
  font-size: 1.25rem;
  font-weight: 700;
  margin-bottom: 0.5rem;
  color: #1a1a1a;
}

.description {
  color: #666;
  line-height: 1.5;
  margin-bottom: 1rem;
}

.footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 1.25rem;
  border-top: 1px solid #eee;
}

.price {
  font-size: 1.5rem;
  font-weight: 700;
  color: #2563eb;
}
// Card.jsx
import styles from './Card.module.css';

function Card({ image, title, description, price, onBuy }) {
  return (
    <div className={styles.card}>
      <img className={styles.image} src={image} alt={title} />
      <div className={styles.content}>
        <h3 className={styles.title}>{title}</h3>
        <p className={styles.description}>{description}</p>
      </div>
      <div className={styles.footer}>
        <span className={styles.price}>{price} Euro</span>
        <button onClick={onBuy}>Kaufen</button>
      </div>
    </div>
  );
}

Globale Klassen in CSS Modules

Manchmal brauchst du globale Klassen:

/* Globale Klasse innerhalb eines Modules */
:global(.visually-hidden) {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
}

/* Compose: Klassen zusammensetzen */
.error {
  composes: button;
  background-color: #e74c3c;
}

Styled Components

Styled Components ist eine CSS-in-JS-Bibliothek, bei der du Styles direkt in JavaScript schreibst:

npm install styled-components

Grundlegende Verwendung

import styled from 'styled-components';

const StyledButton = styled.button`
  padding: 10px 20px;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-size: 1rem;
  background-color: #3498db;
  color: white;
  transition: background-color 0.2s;

  &:hover {
    background-color: #2980b9;
  }
`;

function App() {
  return <StyledButton>Klick mich</StyledButton>;
}

Dynamische Styles mit Props

const Button = styled.button`
  padding: ${props => props.size === 'large' ? '14px 28px' : '10px 20px'};
  font-size: ${props => props.size === 'large' ? '1.125rem' : '1rem'};
  background-color: ${props => {
    switch (props.variant) {
      case 'danger': return '#e74c3c';
      case 'success': return '#27ae60';
      default: return '#3498db';
    }
  }};
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;

  &:hover {
    opacity: 0.9;
  }

  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
`;

// Verwendung
<Button variant="danger" size="large">Loeschen</Button>
<Button variant="success">Speichern</Button>
<Button disabled>Deaktiviert</Button>

Styles erweitern

const BaseButton = styled.button`
  padding: 10px 20px;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-size: 1rem;
`;

const PrimaryButton = styled(BaseButton)`
  background-color: #3498db;
  color: white;
`;

const OutlineButton = styled(BaseButton)`
  background-color: transparent;
  border: 2px solid #3498db;
  color: #3498db;
`;

Theme-Provider

Styled Components hat ein eingebautes Theme-System:

import { ThemeProvider } from 'styled-components';

const lightTheme = {
  colors: {
    primary: '#3498db',
    background: '#ffffff',
    text: '#333333',
    border: '#e5e7eb'
  },
  spacing: {
    sm: '0.5rem',
    md: '1rem',
    lg: '2rem'
  }
};

const darkTheme = {
  colors: {
    primary: '#60a5fa',
    background: '#1a1a2e',
    text: '#e0e0e0',
    border: '#374151'
  },
  spacing: lightTheme.spacing
};

const Card = styled.div`
  background: ${props => props.theme.colors.background};
  color: ${props => props.theme.colors.text};
  border: 1px solid ${props => props.theme.colors.border};
  padding: ${props => props.theme.spacing.lg};
  border-radius: 12px;
`;

function App() {
  const [isDark, setIsDark] = useState(false);

  return (
    <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
      <Card>
        <h2>Theme-Beispiel</h2>
        <button onClick={() => setIsDark(!isDark)}>Theme wechseln</button>
      </Card>
    </ThemeProvider>
  );
}

CSS Modules vs. Styled Components

KriteriumCSS ModulesStyled Components
SyntaxStandard-CSSCSS-in-JS
Dynamische StylesMit Klassen-ToggleDirekt mit Props
Bundle-GroesseKein Extra-JS~12 KB gzipped
LernkurveNiedrigMittel
DevToolsEchte CSS-KlassenGenerierte Klassen
PerformanceSehr gutGut
Server RenderingEinfachBraucht Setup

Empfehlung fuer Einsteiger

  1. Starte mit CSS Modules – einfach, performant, keine Abhaengigkeiten
  2. Nutze Styled Components wenn du viele dynamische Styles brauchst
  3. Erwaege Tailwind CSS fuer schnelle Prototypen und Utility-First-Ansatz

Uebungen

  1. Baue eine Card-Komponente mit CSS Modules inklusive Hover-Effekt und verschiedener Varianten
  2. Erstelle ein Button-System mit Styled Components mit Primary, Secondary und Danger-Varianten
  3. Implementiere einen Dark-Mode mit dem Theme-Provider von Styled Components

Was kommt als Naechstes?

Du kennst jetzt CSS Modules und Styled Components. Im naechsten Kapitel lernst du UI-Bibliotheken wie Material UI und Chakra UI kennen – fertige Komponentenbibliotheken, die dir eine Menge Styling-Arbeit abnehmen.

Zusammenfassung

  • CSS Modules generieren eindeutige Klassen automatisch – keine Namenskonflikte
  • Dateien enden auf .module.css und werden als Objekt importiert
  • Styled Components schreiben CSS direkt in JavaScript mit Template Literals
  • Styled Components unterstuetzen dynamische Styles basierend auf Props
  • CSS Modules sind leichtgewichtiger, Styled Components flexibler
  • Beide Ansaetze eliminieren das Problem globaler CSS-Konflikte

Pro-Tipp: Mische nicht zu viele Styling-Ansaetze in einem Projekt. Entscheide dich fuer einen Hauptansatz (CSS Modules ODER Styled Components ODER Tailwind) und bleibe dabei. Konsistenz ist wichtiger als die “perfekte” Loesung!

Zurück zum React Kurs