Why Mobile-First?
- Performance: Start lean, add features for larger screens
- Touch: Design for touch first, mouse second
- Content: Focus on essential content
- UX: Simpler interfaces, better experiences
Responsive Design
Media Queries
css
/* Mobile first (default) */
.container {
padding: 1rem;
font-size: 16px;
}
/* Tablet */
@media (min-width: 768px) {
.container {
padding: 2rem;
font-size: 18px;
}
}
/* Desktop */
@media (min-width: 1024px) {
.container {
max-width: 1200px;
margin: 0 auto;
padding: 3rem;
}
}Fluid Typography
css
html {
font-size: 16px;
}
h1 {
font-size: clamp(2rem, 5vw, 4rem);
}
p {
font-size: clamp(1rem, 2vw, 1.25rem);
}Touch Targets
css
button,
a {
/* Minimum touch target: 44x44px */
min-height: 44px;
min-width: 44px;
padding: 12px 16px;
}Viewport Meta Tag
html
<meta name="viewport" content="width=device-width, initial-scale=1.0">Grid Layout
css
.grid {
display: grid;
/* Auto-fit: as many as fit */
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1rem;
}Images
html
<!-- Responsive images -->
<img
src="small.jpg"
srcset="small.jpg 400w,
medium.jpg 800w,
large.jpg 1200w"
sizes="(max-width: 600px) 400px,
(max-width: 1200px) 800px,
1200px"
alt="Description"
>
<!-- Modern: <picture> element -->
<picture>
<source media="(max-width: 600px)" srcset="mobile.webp">
<source media="(min-width: 601px)" srcset="desktop.webp">
<img src="fallback.jpg" alt="Description">
</picture>Performance
Lazy Loading
html
<img loading="lazy" src="image.jpg" alt="Description">Critical CSS
html
<style>
/* Inline critical CSS for above-fold content */
body { margin: 0; font-family: sans-serif; }
.hero { padding: 2rem; }
</style>
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">Progressive Enhancement
javascript
// Base functionality works everywhere
function submitForm(form) {
// Traditional form submission
form.submit();
}
// Enhance with JS if available
if ('fetch' in window) {
function submitForm(form) {
event.preventDefault();
fetch('/api/submit', {
method: 'POST',
body: new FormData(form)
}).then(handleResponse);
}
}Mobile UX Patterns
Bottom Navigation
html
<nav class="bottom-nav">
<a href="/">Home</a>
<a href="/search">Search</a>
<a href="/profile">Profile</a>
</nav>
<style>
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: space-around;
padding: 0.75rem;
background: white;
border-top: 1px solid #eee;
}
@media (min-width: 768px) {
.bottom-nav {
display: none;
}
}
</style>Swipe Gestures
javascript
let touchStartX = 0;
let touchEndX = 0;
element.addEventListener('touchstart', e => {
touchStartX = e.changedTouches[0].screenX;
});
element.addEventListener('touchend', e => {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
});
function handleSwipe() {
if (touchEndX < touchStartX - 50) {
// Swipe left
}
if (touchEndX > touchStartX + 50) {
// Swipe right
}
}Testing
javascript
// Test different viewports
// Chrome DevTools > Device Toolbar
// Common breakpoints
// Mobile: 375x667 (iPhone SE)
// Tablet: 768x1024 (iPad)
// Desktop: 1920x1080Mobile-first is user-first!