Mobile-first means designing for the smallest screen first, then progressively enhancing for larger screens. It forces focus on essential content and improves performance.
Why Mobile First?#
Benefits:
✓ Forces content prioritization
✓ Better performance (load less, enhance more)
✓ Easier to scale up than scale down
✓ Mobile traffic often exceeds desktop
✓ Progressive enhancement philosophy
Media Query Strategy#
Mobile First (min-width)#
1/* Base styles (mobile) */
2.container {
3 padding: 1rem;
4 width: 100%;
5}
6
7/* Tablet and up */
8@media (min-width: 768px) {
9 .container {
10 padding: 2rem;
11 max-width: 720px;
12 margin: 0 auto;
13 }
14}
15
16/* Desktop and up */
17@media (min-width: 1024px) {
18 .container {
19 max-width: 960px;
20 }
21}
22
23/* Large desktop */
24@media (min-width: 1280px) {
25 .container {
26 max-width: 1200px;
27 }
28}Breakpoint System#
1:root {
2 /* Breakpoints */
3 --bp-sm: 640px;
4 --bp-md: 768px;
5 --bp-lg: 1024px;
6 --bp-xl: 1280px;
7 --bp-2xl: 1536px;
8}
9
10/* Mixins with CSS custom properties aren't possible,
11 but here's the conceptual approach */
12
13/* Small phones: 0 - 639px (base styles) */
14/* Large phones: 640px+ */
15/* Tablets: 768px+ */
16/* Laptops: 1024px+ */
17/* Desktops: 1280px+ */
18/* Large screens: 1536px+ */Fluid Typography#
1/* Fluid font sizes */
2html {
3 /* Minimum 16px, maximum 20px, scales with viewport */
4 font-size: clamp(1rem, 0.875rem + 0.5vw, 1.25rem);
5}
6
7h1 {
8 /* Minimum 2rem, maximum 4rem */
9 font-size: clamp(2rem, 1.5rem + 2vw, 4rem);
10}
11
12h2 {
13 font-size: clamp(1.5rem, 1.25rem + 1.5vw, 3rem);
14}
15
16/* Line height that adapts */
17p {
18 line-height: calc(1.5em + 0.5vw);
19}Fluid Spacing#
1:root {
2 --space-xs: clamp(0.25rem, 0.2rem + 0.25vw, 0.5rem);
3 --space-sm: clamp(0.5rem, 0.4rem + 0.5vw, 1rem);
4 --space-md: clamp(1rem, 0.8rem + 1vw, 2rem);
5 --space-lg: clamp(2rem, 1.5rem + 2vw, 4rem);
6 --space-xl: clamp(4rem, 3rem + 4vw, 8rem);
7}
8
9.section {
10 padding: var(--space-lg) var(--space-md);
11}
12
13.card {
14 padding: var(--space-md);
15 margin-bottom: var(--space-sm);
16}Responsive Layouts#
CSS Grid#
1/* Auto-fit grid */
2.grid {
3 display: grid;
4 grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
5 gap: 1.5rem;
6}
7
8/* Named areas that change */
9.layout {
10 display: grid;
11 grid-template-areas:
12 "header"
13 "main"
14 "sidebar"
15 "footer";
16 gap: 1rem;
17}
18
19@media (min-width: 768px) {
20 .layout {
21 grid-template-areas:
22 "header header"
23 "sidebar main"
24 "footer footer";
25 grid-template-columns: 250px 1fr;
26 }
27}Flexbox#
1.nav {
2 display: flex;
3 flex-direction: column;
4 gap: 0.5rem;
5}
6
7@media (min-width: 768px) {
8 .nav {
9 flex-direction: row;
10 gap: 2rem;
11 }
12}
13
14/* Responsive cards */
15.card-container {
16 display: flex;
17 flex-wrap: wrap;
18 gap: 1rem;
19}
20
21.card {
22 flex: 1 1 300px; /* Grow, shrink, basis */
23 max-width: 100%;
24}Responsive Images#
1<!-- Art direction with picture -->
2<picture>
3 <source media="(min-width: 1024px)" srcset="hero-desktop.jpg">
4 <source media="(min-width: 768px)" srcset="hero-tablet.jpg">
5 <img src="hero-mobile.jpg" alt="Hero image">
6</picture>
7
8<!-- Resolution switching -->
9<img
10 src="image-400.jpg"
11 srcset="
12 image-400.jpg 400w,
13 image-800.jpg 800w,
14 image-1200.jpg 1200w
15 "
16 sizes="
17 (min-width: 1024px) 33vw,
18 (min-width: 768px) 50vw,
19 100vw
20 "
21 alt="Responsive image"
22>1/* Fluid images */
2img {
3 max-width: 100%;
4 height: auto;
5}
6
7/* Object fit for containers */
8.image-container {
9 aspect-ratio: 16 / 9;
10}
11
12.image-container img {
13 width: 100%;
14 height: 100%;
15 object-fit: cover;
16}Touch Interactions#
1/* Larger touch targets */
2.button {
3 min-height: 44px; /* Apple's recommendation */
4 min-width: 44px;
5 padding: 12px 24px;
6}
7
8/* Touch-friendly spacing */
9.nav-link {
10 padding: 12px 16px;
11 display: block;
12}
13
14/* Remove hover on touch devices */
15@media (hover: none) {
16 .button:hover {
17 /* Don't apply hover styles */
18 background-color: initial;
19 }
20}
21
22/* Hover only on devices that support it */
23@media (hover: hover) {
24 .button:hover {
25 background-color: var(--color-primary-dark);
26 }
27}Navigation Patterns#
1/* Mobile hamburger menu */
2.nav-toggle {
3 display: block;
4}
5
6.nav-menu {
7 position: fixed;
8 top: 0;
9 left: -100%;
10 width: 80%;
11 height: 100vh;
12 transition: left 0.3s ease;
13}
14
15.nav-menu.active {
16 left: 0;
17}
18
19@media (min-width: 768px) {
20 .nav-toggle {
21 display: none;
22 }
23
24 .nav-menu {
25 position: static;
26 width: auto;
27 height: auto;
28 display: flex;
29 }
30}Performance Considerations#
1<!-- Lazy load images -->
2<img src="image.jpg" loading="lazy" alt="Lazy loaded">
3
4<!-- Preload critical resources -->
5<link rel="preload" href="hero-mobile.jpg" as="image" media="(max-width: 767px)">
6<link rel="preload" href="hero-desktop.jpg" as="image" media="(min-width: 768px)">1/* Reduce motion for accessibility */
2@media (prefers-reduced-motion: reduce) {
3 *,
4 *::before,
5 *::after {
6 animation-duration: 0.01ms !important;
7 transition-duration: 0.01ms !important;
8 }
9}Testing Checklist#
Device Testing:
- [ ] iPhone SE (375px)
- [ ] iPhone 14 (390px)
- [ ] iPad (768px)
- [ ] iPad Pro (1024px)
- [ ] Laptop (1280px)
- [ ] Desktop (1920px)
Interactions:
- [ ] Touch targets 44px+
- [ ] No hover-dependent features
- [ ] Swipe gestures work
- [ ] Forms are mobile-friendly
Performance:
- [ ] Images optimized
- [ ] Fonts subset
- [ ] CSS/JS minimal
- [ ] Core Web Vitals passing
Conclusion#
Mobile-first is a mindset, not just a technique. Start with constraints, focus on content, and progressively enhance.
The result is faster sites that work everywhere and serve everyone.