12. Responsive Design
Overview
Dashboard 2.0 implements a mobile-first responsive design strategy with three breakpoints: desktop (1024px+), tablet (768px-1023px), and mobile (320px-767px). This ensures usability across all devices while maintaining productivity for professional use.
Design Philosophy:
- Desktop-first for productivity: Rich features, multiple panels, detailed views
- Tablet for collaboration: Streamlined layouts, touch-friendly interactions
- Mobile for monitoring: Essential information, quick actions, lightweight interface
12.1 Breakpoint Strategy
Three Breakpoints
| Breakpoint | Screen Width | Target Devices | Layout Strategy |
|---|---|---|---|
| Desktop | ≥1024px | Desktop, laptop | Full three-panel layout with sidebar |
| Tablet | 768px-1023px | iPad, Android tablets | Collapsible sidebar, simplified views |
| Mobile | 320px-767px | Phones | Hamburger menu, stacked layout, touch-first |
CSS Media Queries
/* Base styles - Mobile first */
.container {
padding: 16px;
}
/* Tablet (768px+) */
@media (min-width: 768px) {
.container {
padding: 24px;
}
}
/* Desktop (1024px+) */
@media (min-width: 1024px) {
.container {
padding: 32px;
}
}
12.2 Desktop Layout (≥1024px)
Full Three-Panel Layout
Layout Structure:
- Left Sidebar: 280px fixed width (always visible)
- Top Bar: 60px fixed height
- Main Content: calc(100% - 280px) fluid width
CSS Grid:
@media (min-width: 1024px) {
.dashboard-layout {
display: grid;
grid-template-areas:
"sidebar topbar"
"sidebar main";
grid-template-columns: 280px 1fr;
grid-template-rows: 60px 1fr;
height: 100vh;
}
.sidebar {
grid-area: sidebar;
background: #F9FAFB;
border-right: 1px solid #E5E7EB;
}
.topbar {
grid-area: topbar;
background: #FFFFFF;
border-bottom: 1px solid #E5E7EB;
}
.main-content {
grid-area: main;
overflow-y: auto;
}
}
Kanban Board
Desktop-optimized:
- Swimlanes: Full width, all projects visible simultaneously
- Drag-drop: Mouse-based with hover states
- Columns: 3 columns (To Do, In Progress, Done) with equal flex
- Cards: 250px min-width with full details
@media (min-width: 1024px) {
.kanban-board {
display: grid;
grid-template-columns: 250px 1fr 1fr 1fr;
gap: 16px;
}
.task-card {
min-width: 250px;
padding: 16px;
}
.task-card-details {
display: block; /* Show all details */
}
}
12.3 Tablet Layout (768px-1023px)
Collapsible Sidebar
Behavior:
- Default: Sidebar hidden (collapsed)
- Toggle: Hamburger menu button to open/close
- Overlay: Sidebar slides in from left, overlays content
- Tap outside: Close sidebar
CSS:
@media (min-width: 768px) and (max-width: 1023px) {
.dashboard-layout {
display: grid;
grid-template-areas:
"topbar"
"main";
grid-template-columns: 1fr;
grid-template-rows: 60px 1fr;
}
.sidebar {
position: fixed;
top: 0;
left: -280px; /* Hidden by default */
width: 280px;
height: 100vh;
background: #F9FAFB;
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
transition: left 0.3s ease;
z-index: 1000;
}
.sidebar.open {
left: 0; /* Slide in */
}
/* Overlay backdrop */
.sidebar-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
}
.sidebar.open ~ .sidebar-overlay {
display: block;
}
.main-content {
margin-left: 0;
}
}
JavaScript Toggle:
const sidebarToggle = document.getElementById('sidebar-toggle');
const sidebar = document.getElementById('sidebar');
const overlay = document.getElementById('sidebar-overlay');
sidebarToggle.addEventListener('click', () => {
sidebar.classList.toggle('open');
});
overlay.addEventListener('click', () => {
sidebar.classList.remove('open');
});
Simplified Kanban
Tablet-optimized:
- Swimlanes: Collapsible by default, expand one at a time
- Columns: Side-scroll with touch gestures
- Cards: 220px min-width, slightly smaller details
@media (min-width: 768px) and (max-width: 1023px) {
.kanban-board {
overflow-x: auto;
-webkit-overflow-scrolling: touch; /* Smooth iOS scrolling */
}
.swimlane-columns {
display: flex;
gap: 12px;
min-width: min-content;
}
.kanban-column {
min-width: 220px;
flex: 0 0 220px;
}
.task-card {
padding: 12px;
}
.task-card-meta {
font-size: 11px; /* Smaller text */
}
}
12.4 Mobile Layout (320px-767px)
Hamburger Menu Navigation
Full mobile-first navigation:
- Hamburger icon: Top-left corner of top bar
- Full-screen menu: Slides in from left, covers entire screen
- Close button: X icon in top-right of menu
- Touch gestures: Swipe left to close menu
HTML:
<div class="topbar-mobile">
<button class="hamburger-menu" aria-label="Open navigation menu">
<span class="hamburger-icon"></span>
</button>
<h1 class="dashboard-title">Dashboard 2.0</h1>
<button class="search-toggle" aria-label="Open search">🔍</button>
</div>
<div class="mobile-menu" id="mobile-menu">
<div class="mobile-menu-header">
<h2>Navigation</h2>
<button class="close-menu" aria-label="Close menu">✕</button>
</div>
<nav class="mobile-nav">
<!-- Navigation items -->
</nav>
</div>
CSS:
@media (max-width: 767px) {
.dashboard-layout {
display: flex;
flex-direction: column;
}
.topbar-mobile {
display: flex;
align-items: center;
justify-content: space-between;
height: 56px;
padding: 0 16px;
background: #FFFFFF;
border-bottom: 1px solid #E5E7EB;
}
.hamburger-menu {
width: 40px;
height: 40px;
border: none;
background: transparent;
cursor: pointer;
}
.hamburger-icon {
display: block;
width: 24px;
height: 2px;
background: #111827;
position: relative;
}
.hamburger-icon::before,
.hamburger-icon::after {
content: '';
display: block;
width: 24px;
height: 2px;
background: #111827;
position: absolute;
}
.hamburger-icon::before {
top: -8px;
}
.hamburger-icon::after {
top: 8px;
}
/* Mobile Menu */
.mobile-menu {
position: fixed;
top: 0;
left: -100%;
width: 100%;
height: 100vh;
background: #FFFFFF;
transition: left 0.3s ease;
z-index: 2000;
overflow-y: auto;
}
.mobile-menu.open {
left: 0;
}
.mobile-menu-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 56px;
padding: 0 16px;
border-bottom: 1px solid #E5E7EB;
}
.close-menu {
width: 40px;
height: 40px;
border: none;
background: transparent;
font-size: 24px;
cursor: pointer;
}
}
Stacked Content Layout
Mobile-optimized views:
- Portfolio Overview: 1-column grid, cards stack vertically
- Kanban: Horizontal scroll for columns, swipe between projects
- Timeline: Vertical orientation, compressed time scale
- Task Detail: Full-screen modal, bottom sheet slide-up
Portfolio Cards (Mobile):
@media (max-width: 767px) {
.portfolio-grid {
display: flex;
flex-direction: column;
gap: 16px;
}
.kpi-card {
width: 100%;
padding: 16px;
}
.kpi-value {
font-size: 32px; /* Larger for touch targets */
}
.kpi-label {
font-size: 14px;
}
}
Mobile Kanban
Horizontal scroll with snap points:
@media (max-width: 767px) {
.kanban-board {
overflow-x: auto;
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
}
.swimlane {
scroll-snap-align: start;
min-width: 100%;
}
.swimlane-columns {
display: flex;
gap: 12px;
padding: 16px;
}
.kanban-column {
min-width: 280px;
flex: 0 0 280px;
}
.task-card {
padding: 12px;
margin-bottom: 8px;
}
/* Simplified card - hide less important details */
.task-card-assignee,
.task-card-tags {
display: none;
}
}
Mobile Task Detail Modal
Bottom sheet pattern:
@media (max-width: 767px) {
.task-detail-modal {
position: fixed;
bottom: -100%; /* Hidden by default */
left: 0;
width: 100%;
height: 90vh;
background: #FFFFFF;
border-top-left-radius: 16px;
border-top-right-radius: 16px;
box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.1);
transition: bottom 0.3s ease;
z-index: 3000;
}
.task-detail-modal.open {
bottom: 0; /* Slide up */
}
/* Drag handle */
.modal-drag-handle {
width: 40px;
height: 4px;
background: #D1D5DB;
border-radius: 2px;
margin: 12px auto;
}
}
Touch gesture for closing:
let startY = 0;
let currentY = 0;
modal.addEventListener('touchstart', (e) => {
startY = e.touches[0].clientY;
});
modal.addEventListener('touchmove', (e) => {
currentY = e.touches[0].clientY;
const deltaY = currentY - startY;
// Only allow downward swipe
if (deltaY > 0) {
modal.style.transform = `translateY(${deltaY}px)`;
}
});
modal.addEventListener('touchend', () => {
const deltaY = currentY - startY;
// If swiped down >100px, close modal
if (deltaY > 100) {
modal.classList.remove('open');
}
// Reset transform
modal.style.transform = '';
});
12.5 Touch Interactions
Touch-Friendly Targets
Minimum touch target size: 44px × 44px (Apple HIG, Material Design)
/* All interactive elements on touch devices */
@media (hover: none) and (pointer: coarse) {
button,
a,
.clickable {
min-width: 44px;
min-height: 44px;
padding: 12px;
}
.task-card {
padding: 16px; /* More generous padding */
}
.filter-chip {
padding: 10px 16px; /* Larger for touch */
}
}
Swipe Gestures
Kanban column navigation:
let startX = 0;
let currentX = 0;
const kanbanBoard = document.getElementById('kanban-board');
kanbanBoard.addEventListener('touchstart', (e) => {
startX = e.touches[0].clientX;
});
kanbanBoard.addEventListener('touchmove', (e) => {
currentX = e.touches[0].clientX;
});
kanbanBoard.addEventListener('touchend', () => {
const deltaX = startX - currentX;
// Swipe left (next column)
if (deltaX > 50) {
scrollToNextColumn();
}
// Swipe right (previous column)
if (deltaX < -50) {
scrollToPreviousColumn();
}
});
Pull-to-Refresh
Native-like refresh behavior:
let pullDistance = 0;
const threshold = 80;
mainContent.addEventListener('touchstart', (e) => {
if (mainContent.scrollTop === 0) {
startY = e.touches[0].clientY;
}
});
mainContent.addEventListener('touchmove', (e) => {
if (mainContent.scrollTop === 0) {
currentY = e.touches[0].clientY;
pullDistance = currentY - startY;
if (pullDistance > 0 && pullDistance < threshold) {
// Show refresh indicator
showRefreshIndicator(pullDistance / threshold);
}
}
});
mainContent.addEventListener('touchend', () => {
if (pullDistance >= threshold) {
// Trigger refresh
refreshDashboard();
}
// Hide indicator
hideRefreshIndicator();
pullDistance = 0;
});
12.6 Performance Optimization
Lazy Loading
Load content on scroll:
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // Load image
observer.unobserve(img);
}
});
});
// Observe all lazy images
document.querySelectorAll('img[data-src]').forEach(img => {
observer.observe(img);
});
Reduce JavaScript on Mobile
Conditional feature loading:
if (window.innerWidth >= 1024) {
// Load desktop-only features
loadAdvancedFiltering();
loadDragDropLibrary();
} else {
// Mobile-optimized features only
loadTouchGestures();
}
CSS Containment
Improve rendering performance:
.task-card {
contain: layout style paint;
}
.kanban-column {
contain: layout style;
}
12.7 Orientation Changes
Portrait vs. Landscape
Tablet landscape: Show more columns in Kanban Phone landscape: Compress navigation, maximize content
@media (max-width: 767px) and (orientation: landscape) {
.topbar-mobile {
height: 48px; /* Shorter to maximize vertical space */
}
.kanban-column {
min-width: 240px; /* Narrower columns to fit more */
}
}
JavaScript orientation handler:
window.addEventListener('orientationchange', () => {
setTimeout(() => {
// Recalculate layout after orientation change
recalculateLayout();
}, 100);
});
12.8 Implementation Prompt - Responsive Design
Create a responsive dashboard with mobile-first approach.
HTML Structure
<!-- Mobile-first layout -->
<div class="dashboard-layout">
<!-- Mobile Top Bar -->
<div class="topbar-mobile">
<button class="hamburger-menu">☰</button>
<h1 class="dashboard-title">Dashboard</h1>
<button class="search-toggle">🔍</button>
</div>
<!-- Mobile Menu (hidden by default) -->
<div class="mobile-menu" id="mobile-menu">
<!-- Navigation -->
</div>
<!-- Sidebar (tablet/desktop) -->
<aside class="sidebar" id="sidebar">
<!-- Sidebar content -->
</aside>
<!-- Main Content -->
<main class="main-content">
<!-- Dashboard content -->
</main>
</div>
CSS Media Queries
- Base (Mobile): 320px+ with stacked layout
- Tablet: 768px+ with collapsible sidebar
- Desktop: 1024px+ with persistent sidebar
JavaScript Requirements
- Sidebar toggle (tablet)
- Hamburger menu (mobile)
- Touch gestures (swipe, pull-to-refresh)
- Orientation change handler
- Lazy loading for performance
Testing Checklist
Devices to test:
- iPhone SE (320px width)
- iPhone 12/13 (390px)
- iPad (768px)
- iPad Pro (1024px)
- Desktop (1920px+)
Orientations:
- Portrait
- Landscape
Touch interactions:
- Tap targets ≥44px
- Swipe gestures work
- Pull-to-refresh functional
Next: 13. Accessibility (WCAG 2.1 AA) Previous: 11. Global Search Index: Master Index