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

Responsive Design

Overview

p2d2 follows a mobile-first approach with progressive enhancement for desktop devices. The application is optimized for screen sizes from 320px (small smartphones) to 2560px+ (4K displays) and provides optimized touch interactions for mobile devices.

Design Philosophy

Mobile-First

Principle: Design and development start with the smallest screen size.

Advantages:

  • Performance focus from the beginning
  • Progressive enhancement instead of graceful degradation
  • Better touch interactions

Example:

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 DevicesUsage
(default)0pxMobile (Portrait)Base styles
sm640pxMobile (Landscape), large phonesMinor adjustments
md768pxTabletsLayout changes
lg1024pxDesktop, laptopsMulti-column layouts
xl1280pxLarge desktopExtended layouts
2xl1536px4K displaysOptional

Most Common Breakpoints in p2d2

Component Analysis:

  • md (768px): 85% of responsive changes
  • lg (1024px): 10% of changes
  • sm, xl, 2xl: 5% of changes

Recommendation: Focus on md and lg.

Viewport Configuration

Meta Tag

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

Settings:

  • width=device-width: Viewport width = device width
  • initial-scale=1.0: No initial zoom

IMPORTANT: Never use user-scalable=no (accessibility violation)!

iOS Safari Specifics

astro
<!-- Prevents auto-zoom on input focus -->
<style>
  input, select, textarea {
    font-size: 16px; /* Minimum 16px for 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 with padding -->
</div>

Max-Width Graduations:

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 (Most Common Pattern):

astro
<!-- Municipalities overview -->
<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>

Implemented Grid Patterns:

  • grid grid-cols-1 md:grid-cols-3 - Footer, topics
  • grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 - KommunenGrid, KategorienGrid
  • grid grid-cols-1 lg:grid-cols-2 - Contact page, participation page
  • grid grid-cols-1 md:grid-cols-2 - Community page

Flex Layouts

Stack → Row:

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

Header Navigation:

astro
<nav class="flex items-center justify-between px-6 py-4">
  <div class="flex items-center">
    <!-- Logo and 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: Small border-radius */
@media (max-width: 768px) {
  #map {
    clip-path: inset(0 round 12px);
  }
}

/* Desktop: Large border-radius */
@media (min-width: 768px) {
  #map {
    clip-path: inset(0 round 24px);
  }
}

Touch Optimization

Touch Target Sizes

Minimum 44x44px (Apple HIG / WCAG):

astro
<!-- Municipality 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="Select municipality Cologne"
>
  <!-- Sufficiently large touch targets -->
</button>

OpenLayers Touch Interactions

Standard Touch Gestures:

  • Single-Tap: Feature selection
  • Double-Tap: Zoom in
  • Pinch: Zoom
  • Drag: Pan

Implemented Touch Features:

  • Pinch-to-zoom enabled
  • Touch-drag-pan enabled
  • Double-tap-zoom enabled

Municipality Card Touch Handling

Click Handler with Touch Optimization:

typescript
// KommunenClickHandler - Touch-friendly event processing
private handleClick(event: Event): void {
  const target = event.target as HTMLElement;
  
  // Don't block native links!
  if (target.closest("a[href]")) return;
  
  const button = target.closest("button.kommunen-card") as HTMLElement;
  if (!button) return;
  
  // Double-click protection
  if (this.processingButtons.has(button)) {
    return;
  }
  
  this.processingButtons.add(button);
  
  // Touch-friendly processing
  try {
    const slug = button.getAttribute("data-slug");
    if (!slug) return;
    
    // Map navigation and WFS layer management
    this.dispatchKommunenFocus(detail);
    this.handleWFSLayerToggle(detail);
    
  } finally {
    setTimeout(() => {
      this.processingButtons.delete(button);
    }, 500); // Touch debouncing
  }
}

Hover Fallbacks for Touch

Problem: Touch devices don't have :hover

Solution: Active-State + Transition:

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

Typography Scaling

Responsive Font Sizes

Headings:

astro
<h1 class="font-poppins text-2xl md:text-3xl lg:text-4xl font-bold">
  Large heading
</h1>

<h2 class="font-poppins text-xl md:text-2xl lg:text-3xl font-semibold">
  Medium heading
</h2>

Body Text:

astro
<p class="font-inter text-base md:text-lg leading-relaxed">
  Body text with larger font on 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
<!-- Optimal line length: 45-75 characters -->
<article class="max-w-prose mx-auto">
  <p>Text with optimal line length for readability</p>
</article>

Visibility & Display

Conditional Rendering

astro
<!-- Desktop-Only -->
<div class="hidden lg:block">
  Only visible on large screens
</div>

<!-- Mobile-Only -->
<div class="block lg:hidden">
  Only visible on mobile devices
</div>

<!-- Tablet & Desktop -->
<div class="hidden md:block">
  Visible from tablet up
</div>

Tab System Responsive

Map Tabs on 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">
    Municipalities
  </button>
  <button class="tab-button bg-green-500 text-white font-semibold px-6 py-3 rounded-lg">
    Categories
  </button>
</div>

Mobile Tab Button Adjustments:

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

Performance Optimization

Lazy Loading

Components:

astro
<MapCanvas client:load />  <!-- Load map immediately -->

Images:

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

Responsive Section Spacing

CSS Variable for 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);
}

Usage:

astro
<section class="mb-section">
  <!-- Automatically responsive spacing -->
</section>

Code Splitting by Breakpoint

astro
<!-- Mobile-specific JavaScript -->
<script is:inline>
// Touch optimizations only on mobile
if (window.innerWidth < 768) {
  // Mobile-specific initialization
}
</script>

Accessibility (Responsive)

Focus Visible

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

ARIA for Interactive Elements

astro
<button
  aria-label="Select municipality Cologne"
  data-slug="koeln"
  data-kommune-slug="koeln"
>
  Cologne
</button>

Testing

Breakpoint Testing

Browser DevTools:

  1. Chrome DevTools → Device Toolbar (Cmd/Ctrl + Shift + M)
  2. Responsive mode
  3. Test all breakpoints: 320px, 375px, 640px, 768px, 1024px, 1280px

Important Test Devices:

  • 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 first
  2. Test on real device
  3. Progressively enhance for desktop
  4. Avoid desktop-centric thinking

Touch-Friendly

  1. 44x44px minimum for touch targets
  2. Enough spacing between clickable elements
  3. No hover-only interactions
  4. Touch debouncing for fast interactions

Performance

  1. Mobile-first = performance-first
  2. Lazy load everything possible
  3. Use client directives wisely
  4. Optimize responsive images with srcset

Consistency

  1. Use consistent breakpoints
  2. Reuse layout patterns
  3. Keep documentation current

Common Problems & Solutions

Problem: Layout Shift

Symptom: Content jumps during loading

Solution:

astro
<!-- Reserve space for images -->
<img 
  src="/image.jpg" 
  width="800" 
  height="600" 
  class="w-full h-auto"
>

Problem: Horizontal Scroll

Symptom: Page scrolls horizontally on mobile

Solution:

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

Debug:

css
* {
  outline: 1px solid red; /* Find oversized elements */
}

Problem: Touch Event Conflicts

Symptom: Map interactions block card clicks

Solution:

typescript
// Stop event propagation where needed
event.stopPropagation();
// Or: Passive event listeners
element.addEventListener('click', handler, { passive: true });

Checklist

  • [ ] Mobile (320px-640px) tested
  • [ ] Tablet (768px-1024px) tested
  • [ ] Desktop (1280px+) tested
  • [ ] Touch targets ≥ 44x44px
  • [ ] No horizontal scrolls
  • [ ] Mobile navigation works
  • [ ] Map works on touch
  • [ ] Performance: Lighthouse Mobile > 90
  • [ ] Accessibility: WCAG 2.1 AA
  • [ ] Touch debouncing implemented
  • [ ] Responsive images optimized

Implemented Features

✅ Responsive Grid System

  • KommunenGrid: 1 → 2 → 3 columns
  • KategorienGrid: 1 → 2 → 3 columns
  • Footer: 1 → 3 columns
  • Contact: 1 → 2 columns

✅ Touch-Optimized Interactions

  • Municipality card click handler
  • Map touch gestures (pinch, drag, tap)
  • Touch debouncing
  • Active-state fallbacks

✅ Responsive Typography

  • Scaling font sizes
  • Optimal line lengths
  • Mobile-optimized line heights

✅ Performance Optimizations

  • Lazy loading
  • Responsive section spacing
  • Breakpoint-specific code splitting

The responsive design of p2d2 provides a consistent user experience across all device classes with special optimization for touch interactions on mobile devices.