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:
<!-- 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
| Breakpoint | Min-Width | Target-Geräte | Verwendung |
|---|---|---|---|
(default) | 0px | Mobile (Portrait) | Basis-Styles |
sm | 640px | Mobile (Landscape), große Phones | Leichte Anpassungen |
md | 768px | Tablets | Layout-Änderungen |
lg | 1024px | Desktop, Laptops | Multi-Column-Layouts |
xl | 1280px | Large Desktop | Erweiterte Layouts |
2xl | 1536px | 4K-Displays | Optional |
Häufigste Breakpoints in p2d2
Analyse der Komponenten:
md(768px): 85% der Responsive-Änderungenlg(1024px): 10% der Änderungensm,xl,2xl: 5% der Änderungen
Empfehlung: Fokus auf md und lg.
Viewport-Konfiguration
Meta-Tag
<!-- Layout.astro -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">Settings:
width=device-width: Viewport-Breite = Geräte-Breiteinitial-scale=1.0: Kein Initial-Zoom
WICHTIG: Niemals user-scalable=no verwenden (Accessibility-Violation)!
iOS-Safari-Spezifika
<!-- 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:
<div class="w-full md:container md:mx-auto md:px-4">
<!-- Mobile: Full-Width, Desktop: Max-Width mit Padding -->
</div>Max-Width-Abstufungen:
<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):
<!-- 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, Themenbereichegrid grid-cols-1 sm:grid-cols-2 md:grid-cols-3- KommunenGrid, KategorienGridgrid grid-cols-1 lg:grid-cols-2- Kontakt-Seite, Mitmachen-Seitegrid grid-cols-1 md:grid-cols-2- Community-Seite
Flex-Layouts
Stack → Row:
<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:
<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:
<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:
/* 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):
<!-- 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:
// 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:
<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:
<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:
<p class="font-inter text-base md:text-lg leading-relaxed">
Fließtext mit größerer Schrift auf Desktop
</p>Hero-Typography:
<h1 class="font-poppins font-bold text-hero tracking-tight">
<!-- Custom Hero-Size: 3.75rem (60px) -->
</h1>Line-Length (Measure)
<!-- 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
<!-- 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:
<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:
@media (max-width: 640px) {
.tab-button {
min-width: 100px;
padding-left: 4px;
padding-right: 4px;
font-size: 0.875rem;
}
}Performance-Optimierung
Lazy Loading
Components:
<MapCanvas client:load /> <!-- Karte sofort laden -->Images:
<img src="/image.jpg" loading="lazy" alt="Beschreibung">Responsive Section-Spacing
CSS-Variable für responsive Margins:
: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:
<section class="mb-section">
<!-- Automatisch responsive Abstände -->
</section>Code-Splitting nach Breakpoint
<!-- Mobile-spezifisches JavaScript -->
<script is:inline>
// Touch-Optimierungen nur auf Mobile
if (window.innerWidth < 768) {
// Mobile-spezifische Initialisierung
}
</script>Accessibility (Responsive)
Focus-Visible
<button class="focus:outline-none focus-visible:ring-2 focus-visible:ring-primary">
Keyboard-Navigation-Support
</button>ARIA für Interactive Elements
<button
aria-label="Kommune Köln auswählen"
data-slug="koeln"
data-kommune-slug="koeln"
>
Köln
</button>Testing
Breakpoint-Testing
Browser DevTools:
- Chrome DevTools → Device Toolbar (Cmd/Ctrl + Shift + M)
- Responsive-Modus
- 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
# Lighthouse Mobile-Audit
npx lighthouse https://p2d2.example.com --preset=mobile --viewBest Practices
Mobile-First-Workflow
- Design mobile zuerst
- Teste auf echtem Device
- Erweitere progressiv für Desktop
- Vermeide Desktop-zentriertes Denken
Touch-Friendly
- 44x44px Minimum für Touch-Targets
- Genug Spacing zwischen klickbaren Elementen
- Keine Hover-Only-Interactions
- Touch-Debouncing für schnelle Interaktionen
Performance
- Mobile-First = Performance-First
- Lazy Load alles Mögliche
- Client-Directives sinnvoll einsetzen
- Responsive Images mit srcset
Consistency
- Konsistente Breakpoints verwenden
- Layout-Patterns wiederverwenden
- Dokumentation aktuell halten
Häufige Probleme & Lösungen
Problem: Layout-Shift
Symptom: Inhalte springen beim Laden
Lösung:
<!-- 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:
<body class="overflow-x-hidden">Debug:
* {
outline: 1px solid red; /* Finde überbreite Elemente */
}Problem: Touch-Event-Konflikte
Symptom: Map-Interaktionen blockieren Card-Clicks
Lösung:
// 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.