Zum Hauptinhalt springen
CSS-Optimierung Teil 2: Architektur & Wartbarkeit
#CSS #Architektur #Wartbarkeit #BEM

CSS-Optimierung Teil 2: Architektur & Wartbarkeit


Codebase die groß werden darf und trotzdem nicht nervt - Selektoren, Layers, Tokens & Dead CSS

6 Minuten Lesezeit

Performance ist wichtig. Aber wenn dein CSS nach 6 Monaten ein Wartungs-Albtraum ist, nützt dir die beste Performance nichts.

Dieser Teil zeigt, wie du CSS schreibst, das skaliert.

1. Selector-Strategien & Spezifität

Das Spezifitäts-Problem

/* Tag: 1 Punkt */
div { color: black; }

/* Klasse: 10 Punkte */
.button { color: blue; }

/* ID: 100 Punkte */
#header { color: red; }

/* Inline: 1000 Punkte */
<div style="color: green;">

/* !important: ∞ Punkte */
.text { color: purple !important; }

Problem: Einmal !important, immer !important.

/* ❌ Spezifitäts-Hölle */
.button { background: blue; }
.button.primary { background: green !important; }
.button.primary.large { background: red !important; }

BEM: Block Element Modifier

/* ✅ Flache Spezifität */
.button { }
.button__icon { }
.button__text { }
.button--primary { }
.button--large { }

Vorteile:

  • Immer gleiche Spezifität (10 Punkte)
  • Keine Verschachtelung
  • Selbstdokumentierend

Nachteile:

  • Lange Klassennamen
  • HTML wird “hässlich”

Utility-First (Tailwind-Stil)

<!-- ✅ Komponierbar, keine Spezifität -->
<button class="px-4 py-2 bg-blue-500 text-white rounded">
  Click me
</button>

Vorteile:

  • Keine CSS-Datei schreiben
  • Keine Dead CSS
  • Konsistent

Nachteile:

  • HTML wird lang
  • Repetitiv

Hybrid-Ansatz (Best Practice)

/* Base Komponente */
.button {
  @apply px-4 py-2 rounded font-medium;
}

/* Varianten mit Data-Attributes */
.button[data-variant="primary"] {
  @apply bg-blue-500 text-white;
}

.button[data-size="large"] {
  @apply px-6 py-3 text-lg;
}
<button class="button" data-variant="primary" data-size="large">
  Click me
</button>

Vorteil: Lesbar + wartbar + kein Spezifitäts-Krieg.

!important vermeiden

Legitime Nutzung:

/* ✅ OK - Utility-Klassen */
.hidden { display: none !important; }
.sr-only { position: absolute !important; }

Illegitime Nutzung:

/* ❌ Schlecht - Quick Fix */
.header { 
  margin-top: 20px !important; /* Warum nicht 20px? */
}

Lösung: Spezifität erhöhen oder Selektor umstrukturieren.


2. CSS-Architektur: Layers, Tokens, Utilities

@layer für Ordnung

/* ✅ Definiere Layer-Reihenfolge */
@layer reset, base, components, utilities;

@layer reset {
  * { margin: 0; padding: 0; box-sizing: border-box; }
}

@layer base {
  body { font-family: sans-serif; }
  h1 { font-size: 2rem; }
}

@layer components {
  .button { padding: 0.5rem 1rem; }
  .card { border: 1px solid #ccc; }
}

@layer utilities {
  .text-center { text-align: center !important; }
}

Vorteil: Utilities überschreiben immer Components, egal wo sie im Code stehen.

Design Tokens

:root {
  /* Colors */
  --color-primary: #3b82f6;
  --color-primary-dark: #2563eb;
  --color-primary-light: #60a5fa;
  
  --color-gray-50: #f9fafb;
  --color-gray-900: #111827;
  
  /* Spacing */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  
  /* Typography */
  --font-sans: 'Inter', sans-serif;
  --font-mono: 'Fira Code', monospace;
  
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  
  /* Shadows */
  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
  
  /* Radius */
  --radius-sm: 0.25rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;
}

/* Komponenten nutzen Tokens */
.button {
  padding: var(--space-2) var(--space-4);
  background: var(--color-primary);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}

Vorteil: Ein Token ändern = alle Komponenten ändern sich.

Utilities vs. Komponenten

Faustregel:

  • Komponente: Wird mehrfach verwendet, hat eigene Logik
  • Utility: Atomare Helper-Klasse
/* ✅ Komponente */
.card {
  padding: var(--space-4);
  background: white;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

/* ✅ Utilities */
.mt-4 { margin-top: var(--space-4); }
.flex { display: flex; }
.items-center { align-items: center; }

3. Dead CSS & Bloat vermeiden

Das Problem

/* styles.css - 500 KB */
.button-legacy { } /* Wird nirgendwo genutzt */
.old-header { } /* Wurde ersetzt */
.test-class { } /* Vergessen zu löschen */

Nach 2 Jahren: 70% Dead CSS.

Detection Tools

PurgeCSS:

// purgecss.config.js
module.exports = {
  content: ['./src/**/*.html', './src/**/*.js'],
  css: ['./src/**/*.css'],
  defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
}

UnCSS:

npm install -g uncss
uncss index.html > cleaned.css

Chrome DevTools Coverage:

  1. DevTools → More Tools → Coverage
  2. Reload page
  3. Siehe rote Balken = ungenutztes CSS

Präventiv vermeiden

Strategie 1: Utility-First

<!-- Kein Dead CSS möglich -->
<div class="p-4 bg-white rounded shadow">

Strategie 2: CSS-in-JS / CSS Modules

// Nur genutztes CSS wird gebundelt
import styles from './Button.module.css';

<button className={styles.primary}>Click</button>

Strategie 3: Scoped Styles

<!-- Vue: Scoped = nur für diese Komponente -->
<style scoped>
.button { color: blue; }
</style>

Namenskonventionen

/* ✅ Klar wo es genutzt wird */
.home-hero { }
.blog-sidebar { }
.checkout-button { }

/* ❌ Unklar */
.box { }
.content { }
.item { }

4. Theming & Dark Mode

CSS Custom Properties

/* Light Theme (Default) */
:root {
  --bg-primary: #ffffff;
  --text-primary: #111827;
  --border-color: #e5e7eb;
}

/* Dark Theme */
:root[data-theme="dark"] {
  --bg-primary: #111827;
  --text-primary: #f9fafb;
  --border-color: #374151;
}

/* Komponenten nutzen Tokens */
.card {
  background: var(--bg-primary);
  color: var(--text-primary);
  border: 1px solid var(--border-color);
}

prefers-color-scheme

/* Automatisch OS-Theme folgen */
@media (prefers-color-scheme: dark) {
  :root {
    --bg-primary: #111827;
    --text-primary: #f9fafb;
  }
}

Mit User-Override

/* Default: OS folgen */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --bg-primary: #111827;
  }
}

/* User wählt explizit Light */
:root[data-theme="light"] {
  --bg-primary: #ffffff;
}

/* User wählt explizit Dark */
:root[data-theme="dark"] {
  --bg-primary: #111827;
}
// Theme-Toggle
function setTheme(theme) {
  document.documentElement.setAttribute('data-theme', theme);
  localStorage.setItem('theme', theme);
}

// Initiales Laden
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
  setTheme(savedTheme);
}

Performance & Lesbarkeit

❌ Schlecht:

.button {
  background: #3b82f6;
  color: white;
}

.button-dark {
  background: #60a5fa;
  color: #111827;
}

✅ Gut:

.button {
  background: var(--color-primary);
  color: var(--color-on-primary);
}

Vorteil:

  • Ein Theme-Toggle ändert alle Komponenten
  • Keine Duplikation
  • Lesbar

Color-Scheme Property

/* Browser-UI anpassen */
:root {
  color-scheme: light dark;
}

/* Form-Controls folgen Theme */
:root[data-theme="dark"] {
  color-scheme: dark;
}

Effekt: Scrollbars, Inputs, Checkboxen passen sich an.


KI-Audit: Architektur & Wartbarkeit prüfen

Kopiere diesen Prompt in Claude, ChatGPT oder deine bevorzugte KI:

Analysiere mein Projekt auf CSS-Architektur und Wartbarkeits-Probleme:

1. **Spezifität**: Finde ID-Selektoren (#id) und verschachtelte Selektoren (> 3 Ebenen). Schlage BEM-Alternativen vor.

2. **!important Missbrauch**: Wo wird !important verwendet? Ist es berechtigt (Utilities) oder ein Code-Smell?

3. **@layer Struktur**: Nutze ich @layer? Falls nein, zeige wie ich reset, base, components, utilities organisiere.

4. **Magic Numbers**: Finde hart-codierte Werte (colors, spacing, font-sizes). Schlage Design Tokens via CSS Custom Properties vor.

5. **Duplizierter Code**: Finde wiederkehrende Patterns (gleiche Farben, Abstände, Schatten). Zeige Consolidation-Möglichkeiten.

6. **Dead CSS**: Nutze ich Klassen die nirgends im HTML vorkommen?

7. **Theming**: Prüfe ob Hard-coded Colors existieren die variabel sein sollten (Dark Mode Support).

Gib mir konkrete Refactoring-Vorschläge mit Priorität (kritisch/wichtig/nice-to-have).

Links: