Zum Hauptinhalt springen
CSS-Optimierung Teil 4: Zugänglichkeit & Lesbarkeit
#CSS #Accessibility #A11y #Typografie #UX

CSS-Optimierung Teil 4: Zugänglichkeit & Lesbarkeit


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

6 Minuten Lesezeit

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: