Skip to content
🔵Entwurf (gut)62%
Vollständigkeit:
80%
Korrektheit:
75%
⏳ Noch nicht geprüft

Responsive Design

Übersicht

p2d2 folgt einem Mobile-First-Ansatz mit progressivem Enhancement für Desktop-Geräte. Die Anwendung ist für Bildschirmgrößen von 320px (kleine Smartphones) bis 2560px+ (4K-Displays) optimiert und bietet optimierte Touch-Interaktionen für mobile Geräte.

Design-Philosophie

Mobile-First

Prinzip: Design und Entwicklung beginnen mit der kleinsten Bildschirmgröße.

Vorteile:

  • Performance-Fokus von Anfang an
  • Progressive Enhancement statt Graceful Degradation
  • Bessere Touch-Interaktionen

Beispiel:

astro
<!-- Base: Mobile (< 640px) -->
<div class="flex flex-col gap-2">
  
  <!-- Tablet (≥ 768px) -->
  <div class="md:flex-row md:gap-4">
  
    <!-- Desktop (≥ 1024px) -->
    <div class="lg:gap-6">

Breakpoint-System

Tailwind Breakpoints

BreakpointMin-WidthTarget-GeräteVerwendung
(default)0pxMobile (Portrait)Basis-Styles
sm640pxMobile (Landscape), große PhonesLeichte Anpassungen
md768pxTabletsLayout-Änderungen
lg1024pxDesktop, LaptopsMulti-Column-Layouts
xl1280pxLarge DesktopErweiterte Layouts
2xl1536px4K-DisplaysOptional

Häufigste Breakpoints in p2d2

Analyse der Komponenten:

  • md (768px): 85% der Responsive-Änderungen
  • lg (1024px): 10% der Änderungen
  • sm, xl, 2xl: 5% der Änderungen

Empfehlung: Fokus auf md und lg.

Viewport-Konfiguration

Meta-Tag

astro
<!-- Layout.astro -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">

Settings:

  • width=device-width: Viewport-Breite = Geräte-Breite
  • initial-scale=1.0: Kein Initial-Zoom

WICHTIG: Niemals user-scalable=no verwenden (Accessibility-Violation)!

iOS-Safari-Spezifika

astro
<!-- Verhindert Auto-Zoom bei Input-Focus -->
<style>
  input, select, textarea {
    font-size: 16px; /* Mindestens 16px für iOS */
  }
</style>

Responsive Layout-Patterns

Container-System

Full-Width → Constrained:

astro
<div class="w-full md:container md:mx-auto md:px-4">
  <!-- Mobile: Full-Width, Desktop: Max-Width mit Padding -->
</div>

Max-Width-Abstufungen:

astro
<div class="max-w-full md:max-w-3xl lg:max-w-5xl xl:max-w-7xl mx-auto">

Grid-Layouts

Responsive Grid-Columns (Häufigstes Pattern):

astro
<!-- Kommunen-Übersicht -->
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 md:gap-6">
  {kommunen.map(kommune => (
    <KommuneCard data={kommune} />
  ))}
</div>

Implementierte Grid-Patterns:

  • grid grid-cols-1 md:grid-cols-3 - Footer, Themenbereiche
  • grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 - KommunenGrid, KategorienGrid
  • grid grid-cols-1 lg:grid-cols-2 - Kontakt-Seite, Mitmachen-Seite
  • grid grid-cols-1 md:grid-cols-2 - Community-Seite

Flex-Layouts

Stack → Row:

astro
<div class="flex flex-col md:flex-row gap-4">
  <div class="w-full md:w-1/2">Links</div>
  <div class="w-full md:w-1/2">Rechts</div>
</div>

Header-Navigation:

astro
<nav class="flex items-center justify-between px-6 py-4">
  <div class="flex items-center">
    <!-- Logo und Navigation -->
  </div>
</nav>

Map-Container

Responsive Height:

astro
<div class="w-full h-[30rem] text-lg text-grey-900 mb-8 text-center relative">
  <main class="w-full h-full">
    <MapCanvas />
  </main>
</div>

MapCanvas Responsive Styling:

css
/* Mobile: Kleine Border-Radius */
@media (max-width: 768px) {
  #map {
    clip-path: inset(0 round 12px);
  }
}

/* Desktop: Große Border-Radius */
@media (min-width: 768px) {
  #map {
    clip-path: inset(0 round 24px);
  }
}

Touch-Optimierung

Touch-Target-Größen

Minimum 44x44px (Apple HIG / WCAG):

astro
<!-- Kommunen-Card Buttons -->
<button 
  type="button"
  class="kommunen-card relative bg-white rounded-xl border border-gray-200 shadow-lg overflow-hidden transition-all duration-300 hover:-translate-y-2 hover:shadow-2xl group text-left w-full h-full flex flex-col"
  aria-label="Kommune Köln auswählen"
>
  <!-- Ausreichend große Touch-Targets -->
</button>

OpenLayers Touch-Interactions

Standard-Touch-Gesten:

  • Single-Tap: Feature-Selection
  • Double-Tap: Zoom-In
  • Pinch: Zoom
  • Drag: Pan

Implementierte Touch-Features:

  • Pinch-to-Zoom aktiviert
  • Touch-Drag-Pan aktiviert
  • Doppel-Tap-Zoom aktiviert

Kommunen-Card Touch-Handling

Click-Handler mit Touch-Optimierung:

typescript
// KommunenClickHandler - Touch-freundliche Event-Verarbeitung
private handleClick(event: Event): void {
  const target = event.target as HTMLElement;
  
  // Native Links nicht blockieren!
  if (target.closest("a[href]")) return;
  
  const button = target.closest("button.kommunen-card") as HTMLElement;
  if (!button) return;
  
  // Double-Click-Schutz
  if (this.processingButtons.has(button)) {
    return;
  }
  
  this.processingButtons.add(button);
  
  // Touch-freundliche Verarbeitung
  try {
    const slug = button.getAttribute("data-slug");
    if (!slug) return;
    
    // Map-Navigation und WFS-Layer-Management
    this.dispatchKommunenFocus(detail);
    this.handleWFSLayerToggle(detail);
    
  } finally {
    setTimeout(() => {
      this.processingButtons.delete(button);
    }, 500); // Touch-Debouncing
  }
}

Hover-Fallbacks für Touch

Problem: Touch-Geräte haben kein :hover

Lösung: Active-State + Transition:

astro
<button class="kommunen-card transition-all duration-300 hover:-translate-y-2 active:scale-95">
  <!-- active: funktioniert auf Touch -->
</button>

Typography-Skalierung

Responsive Font-Sizes

Headings:

astro
<h1 class="font-poppins text-2xl md:text-3xl lg:text-4xl font-bold">
  Große Überschrift
</h1>

<h2 class="font-poppins text-xl md:text-2xl lg:text-3xl font-semibold">
  Mittlere Überschrift
</h2>

Body-Text:

astro
<p class="font-inter text-base md:text-lg leading-relaxed">
  Fließtext mit größerer Schrift auf Desktop
</p>

Hero-Typography:

astro
<h1 class="font-poppins font-bold text-hero tracking-tight">
  <!-- Custom Hero-Size: 3.75rem (60px) -->
</h1>

Line-Length (Measure)

astro
<!-- Optimale Zeilenlänge: 45-75 Zeichen -->
<article class="max-w-prose mx-auto">
  <p>Text mit optimaler Zeilenlänge für Lesbarkeit</p>
</article>

Sichtbarkeit & Display

Conditional Rendering

astro
<!-- Desktop-Only -->
<div class="hidden lg:block">
  Nur auf großen Bildschirmen sichtbar
</div>

<!-- Mobile-Only -->
<div class="block lg:hidden">
  Nur auf mobilen Geräten sichtbar
</div>

<!-- Tablet & Desktop -->
<div class="hidden md:block">
  Ab Tablet sichtbar
</div>

Tab-System Responsive

Map-Tabs auf Mobile:

astro
<div class="absolute bottom-4 left-1/2 transform -translate-x-1/2 z-50 flex gap-3">
  <button class="tab-button active bg-orange-500 text-white font-semibold px-6 py-3 rounded-lg">
    Kommunen
  </button>
  <button class="tab-button bg-green-500 text-white font-semibold px-6 py-3 rounded-lg">
    Kategorien
  </button>
</div>

Mobile Tab-Button Anpassungen:

css
@media (max-width: 640px) {
  .tab-button {
    min-width: 100px;
    padding-left: 4px;
    padding-right: 4px;
    font-size: 0.875rem;
  }
}

Performance-Optimierung

Lazy Loading

Components:

astro
<MapCanvas client:load />  <!-- Karte sofort laden -->

Images:

astro
<img src="/image.jpg" loading="lazy" alt="Beschreibung">

Responsive Section-Spacing

CSS-Variable für responsive Margins:

css
:root {
  --mb-section: 2rem;
}
@media (min-width: 640px) {
  :root {
    --mb-section: 3rem;
  }
}
@media (min-width: 768px) {
  :root {
    --mb-section: 4rem;
  }
}
@media (min-width: 1024px) {
  :root {
    --mb-section: 5.5rem;
  }
}

.mb-section {
  margin-bottom: var(--mb-section, 1rem);
}

Verwendung:

astro
<section class="mb-section">
  <!-- Automatisch responsive Abstände -->
</section>

Code-Splitting nach Breakpoint

astro
<!-- Mobile-spezifisches JavaScript -->
<script is:inline>
// Touch-Optimierungen nur auf Mobile
if (window.innerWidth < 768) {
  // Mobile-spezifische Initialisierung
}
</script>

Accessibility (Responsive)

Focus-Visible

astro
<button class="focus:outline-none focus-visible:ring-2 focus-visible:ring-primary">
  Keyboard-Navigation-Support
</button>

ARIA für Interactive Elements

astro
<button
  aria-label="Kommune Köln auswählen"
  data-slug="koeln"
  data-kommune-slug="koeln"
>
  Köln
</button>

Testing

Breakpoint-Testing

Browser DevTools:

  1. Chrome DevTools → Device Toolbar (Cmd/Ctrl + Shift + M)
  2. Responsive-Modus
  3. Teste alle Breakpoints: 320px, 375px, 640px, 768px, 1024px, 1280px

Wichtige Test-Geräte:

  • iPhone SE (320px)
  • iPhone 12/13 (390px)
  • iPad (768px)
  • Desktop (1920px)

Touch-Testing

  • iOS Safari (iOS 15+)
  • Chrome Mobile (Android)
  • Tablet-Devices

Performance-Testing

bash
# Lighthouse Mobile-Audit
npx lighthouse https://p2d2.example.com --preset=mobile --view

Best Practices

Mobile-First-Workflow

  1. Design mobile zuerst
  2. Teste auf echtem Device
  3. Erweitere progressiv für Desktop
  4. Vermeide Desktop-zentriertes Denken

Touch-Friendly

  1. 44x44px Minimum für Touch-Targets
  2. Genug Spacing zwischen klickbaren Elementen
  3. Keine Hover-Only-Interactions
  4. Touch-Debouncing für schnelle Interaktionen

Performance

  1. Mobile-First = Performance-First
  2. Lazy Load alles Mögliche
  3. Client-Directives sinnvoll einsetzen
  4. Responsive Images mit srcset

Consistency

  1. Konsistente Breakpoints verwenden
  2. Layout-Patterns wiederverwenden
  3. Dokumentation aktuell halten

Häufige Probleme & Lösungen

Problem: Layout-Shift

Symptom: Inhalte springen beim Laden

Lösung:

astro
<!-- Reserviere Platz für Bilder -->
<img 
  src="/image.jpg" 
  width="800" 
  height="600" 
  class="w-full h-auto"
>

Problem: Horizontal-Scroll

Symptom: Seite scrollt horizontal auf Mobile

Lösung:

astro
<body class="overflow-x-hidden">

Debug:

css
* {
  outline: 1px solid red; /* Finde überbreite Elemente */
}

Problem: Touch-Event-Konflikte

Symptom: Map-Interaktionen blockieren Card-Clicks

Lösung:

typescript
// Event-Propagation stoppen wo nötig
event.stopPropagation();
// Oder: Passive Event-Listener
element.addEventListener('click', handler, { passive: true });

Checkliste

  • [ ] Mobile (320px-640px) getestet
  • [ ] Tablet (768px-1024px) getestet
  • [ ] Desktop (1280px+) getestet
  • [ ] Touch-Targets ≥ 44x44px
  • [ ] Keine Horizontal-Scrolls
  • [ ] Mobile-Navigation funktioniert
  • [ ] Karte funktioniert auf Touch
  • [ ] Performance: Lighthouse Mobile > 90
  • [ ] Accessibility: WCAG 2.1 AA
  • [ ] Touch-Debouncing implementiert
  • [ ] Responsive Images optimiert

Implementierte Features

✅ Responsive Grid-System

  • KommunenGrid: 1 → 2 → 3 Spalten
  • KategorienGrid: 1 → 2 → 3 Spalten
  • Footer: 1 → 3 Spalten
  • Kontakt: 1 → 2 Spalten

✅ Touch-Optimierte Interaktionen

  • Kommunen-Card Click-Handler
  • Map-Touch-Gesten (Pinch, Drag, Tap)
  • Touch-Debouncing
  • Active-State Fallbacks

✅ Responsive Typography

  • Skalierende Font-Sizes
  • Optimale Zeilenlängen
  • Mobile-optimierte Line-Heights

✅ Performance-Optimierungen

  • Lazy Loading
  • Responsive Section-Spacing
  • Breakpoint-spezifisches Code-Splitting

Das Responsive Design von p2d2 bietet eine konsistente Benutzererfahrung über alle Geräteklassen hinweg mit spezieller Optimierung für Touch-Interaktionen auf mobilen Geräten.