CSS-Optimierung Teil 4: Zugänglichkeit & Lesbarkeit

CSS für Menschen optimiert - Typografie, Focus-States, Motion & Barrierefreiheit

6 Minuten
CSS-Optimierung Teil 4: Zugänglichkeit & Lesbarkeit
#CSS #Accessibility #A11y #Typografie

Schnelles CSS ist wichtig. Aber wenn Nutzer deine Seite nicht lesen oder bedienen können, ist alle Performance umsonst.

Dieser Teil zeigt, wie du CSS für Menschen optimierst.

1. Typografie & Lesbarkeit

Line-Height & Measure

/* ❌ Unleserlich */
.text {
  line-height: 1;
  max-width: 100%;
}

/* ✅ Lesbar */
.text {
  line-height: 1.6; /* Fließtext: 1.5-1.8 */
  max-width: 65ch; /* 45-75 Zeichen pro Zeile */
}

ch-Unit: Breite des “0”-Zeichens. 65ch ≈ 65 Zeichen.

WCAG-Empfehlung: Max. 80 Zeichen pro Zeile.

Responsive Font-Scaling mit clamp()

/* ❌ Sprunghaft */
body {
  font-size: 16px;
}

@media (min-width: 768px) {
  body { font-size: 18px; }
}

@media (min-width: 1024px) {
  body { font-size: 20px; }
}

/* ✅ Fluid */
body {
  font-size: clamp(1rem, 0.875rem + 0.5vw, 1.25rem);
  /*            min     fluid           max    */
}

h1 {
  font-size: clamp(2rem, 1.5rem + 2vw, 3.5rem);
}

Vorteil: Smooth Scaling, keine Breakpoints nötig.

Kontrast & Farben

WCAG AA (Minimum):

  • Normal text: 4.5
  • Large text (18pt+): 3

WCAG AAA (Enhanced):

  • Normal text: 7
  • Large text: 4.5
/* ❌ Zu wenig Kontrast */
.text {
  color: #999; /* 2.8:1 auf weiß */
  background: #fff;
}

/* ✅ Ausreichend */
.text {
  color: #666; /* 5.7:1 auf weiß */
  background: #fff;
}

Tools:

Font-Features

/* Typografie-Features aktivieren */
body {
  font-feature-settings: 
    "kern" 1,  /* Kerning */
    "liga" 1,  /* Ligaturen */
    "calt" 1;  /* Contextual Alternates */
}

/* Tabellarische Zahlen */
.price {
  font-variant-numeric: tabular-nums;
}

Responsive Typography Scale

:root {
  /* Typographic Scale - Major Third (1.25) */
  --text-xs: clamp(0.64rem, 0.6rem + 0.2vw, 0.8rem);
  --text-sm: clamp(0.8rem, 0.75rem + 0.25vw, 1rem);
  --text-base: clamp(1rem, 0.94rem + 0.31vw, 1.25rem);
  --text-lg: clamp(1.25rem, 1.18rem + 0.39vw, 1.56rem);
  --text-xl: clamp(1.56rem, 1.47rem + 0.49vw, 1.95rem);
  --text-2xl: clamp(1.95rem, 1.84rem + 0.61vw, 2.44rem);
  --text-3xl: clamp(2.44rem, 2.3rem + 0.76vw, 3.05rem);
}

h1 { font-size: var(--text-3xl); }
h2 { font-size: var(--text-2xl); }
h3 { font-size: var(--text-xl); }
p { font-size: var(--text-base); }
small { font-size: var(--text-sm); }

2. Focus-States & Interaktionen

Sichtbare Focus-Stile

/* ❌ NIEMALS! */
*:focus {
  outline: none;
}

/* ✅ Custom Focus */
*:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* ✅ Noch besser mit :focus-visible */
*:focus {
  outline: none;
}

*:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

Unterschied:

  • :focus - Immer bei Focus (auch Maus-Klick)
  • :focus-visible - Nur bei Tastatur-Navigation

Focus-Within für Gruppen

/* Form-Gruppe highlighten bei Focus */
.form-group:focus-within {
  background: rgba(59, 130, 246, 0.05);
  border-color: var(--color-primary);
}

/* Navigation-Container bei Focus */
.nav:focus-within {
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);
}

Hover vs. Touch

/* ❌ Probleme auf Touch */
.button:hover {
  transform: scale(1.1);
}

/* ✅ Nur auf Devices mit Hover */
@media (hover: hover) {
  .button:hover {
    transform: scale(1.05);
  }
}

/* Touch-Feedback */
.button:active {
  transform: scale(0.98);
}

Keyboard-Navigation

/* Skip Links */
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px;
  z-index: 100;
}

.skip-link:focus {
  top: 0;
}
<a href="#main-content" class="skip-link">
  Skip to main content
</a>

Interactive Elements Sizing

/* ❌ Zu klein für Touch */
.button {
  padding: 4px 8px;
}

/* ✅ WCAG AAA: Min. 44x44px */
.button {
  min-width: 44px;
  min-height: 44px;
  padding: 12px 24px;
}

/* Links im Fließtext */
a {
  /* Min. 24px Touch-Target */
  padding: 2px 0;
  margin: -2px 0;
}

3. Motion & Barrierefreiheit

prefers-reduced-motion

/* Standard: Animationen */
.card {
  transition: transform 0.3s, box-shadow 0.3s;
}

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

/* Reduced Motion: Weniger/keine Animation */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  
  /* Wichtige Animationen sehr kurz */
  .modal {
    animation-duration: 0.1s !important;
  }
}

Safe Animations

/* ✅ Diese sind OK auch ohne Reduced Motion */
.element {
  /* Opacity */
  transition: opacity 0.3s;
}

.element {
  /* Farben */
  transition: background-color 0.3s;
}

.element {
  /* Transform (wenig Bewegung) */
  transition: transform 0.2s;
}

/* ⚠️ Diese können problematisch sein */
.element {
  /* Große Bewegungen */
  animation: spin 2s infinite;
}

.element {
  /* Blinkende Effekte */
  animation: flash 0.5s infinite;
}

Keine kritischen Infos nur animiert

/* ❌ Error-Hinweis nur durch Animation */
.input.error {
  animation: shake 0.5s;
}

/* ✅ Zusätzlich visuelle Marker */
.input.error {
  border-color: red;
  animation: shake 0.5s;
}

.input.error::after {
  content: '✗';
  color: red;
}

Parallax & Scroll-Triggered Animations

/* Parallax nur wenn User OK damit */
@media (prefers-reduced-motion: no-preference) {
  .parallax {
    background-attachment: fixed;
  }
}

@media (prefers-reduced-motion: reduce) {
  .parallax {
    background-attachment: scroll;
  }
}

Bonus: Weitere Accessibility-Features

Screen-Reader Only Content

/* Visuell versteckt, für Screen Reader sichtbar */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

/* Bei Focus sichtbar (Skip Links) */
.sr-only:focus {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
  white-space: normal;
}

High Contrast Mode

/* Windows High Contrast */
@media (prefers-contrast: high) {
  .button {
    border: 2px solid;
  }
  
  .card {
    border: 1px solid;
  }
}

Forced Colors Mode

/* Windows Forced Colors */
@media (forced-colors: active) {
  .button {
    border: 1px solid;
  }
  
  /* Icons sichtbar machen */
  .icon {
    forced-color-adjust: auto;
  }
}
@media print {
  /* Links sichtbar machen */
  a::after {
    content: " (" attr(href) ")";
  }
  
  /* Unnötiges ausblenden */
  nav,
  .sidebar,
  .ads {
    display: none;
  }
  
  /* Seitenumbrüche */
  h1,
  h2,
  h3 {
    page-break-after: avoid;
  }
  
  /* Farben für Druck optimieren */
  body {
    color: #000;
    background: #fff;
  }
}

KI-Audit: Accessibility & Lesbarkeit prüfen

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

Analysiere mein Projekt auf Accessibility und Lesbarkeits-Probleme:

1. **Kontrast-Ratio**: Prüfe alle Farb-Kombinationen. Erreichen sie WCAG AA (4.5:1 normal, 3:1 large)?

2. **Focus States**: Haben interaktive Elemente sichtbare Focus-Styles? Nutze ich `:focus-visible`?

3. **Touch Targets**: Sind alle Buttons/Links mindestens 44x44px? Wo fehlt ausreichend Padding?

4. **Typografie**: 
   - `line-height` zwischen 1.5-2?
   - `max-width` für Lesefluss (60-75 Zeichen)?
   - `font-size` mindestens 16px?

5. **Motion Sensitivity**: Respektiere ich `prefers-reduced-motion`? Gibt es Animationen die nicht deaktiviert werden?

6. **Farbe als Info**: Zeige ich kritische Infos nur durch Farbe (z.B. nur rote Fehler ohne Icon/Text)?

7. **Screen Reader**: Sind dekorative Elemente mit `aria-hidden="true"` markiert?

Gib mir eine WCAG-konforme Checkliste mit konkreten Fixes.

Links: