Responsive Layout Strategies
Master mobile-first responsive design with fluid layouts, modern CSS techniques, and strategies that ensure your theme looks great on every device.
Over half of e-commerce traffic comes from mobile devices. A responsive theme isn’t optional. Let’s explore strategies for building layouts that adapt gracefully to any screen size.
Mobile-First Approach
Write base styles for mobile, then add complexity for larger screens:
/* Base: Mobile styles */.product-grid { display: grid; grid-template-columns: 1fr; gap: var(--spacing-md);}
/* Tablet and up */@media (min-width: 768px) { .product-grid { grid-template-columns: repeat(2, 1fr); }}
/* Desktop */@media (min-width: 1024px) { .product-grid { grid-template-columns: repeat(3, 1fr); }}
/* Large desktop */@media (min-width: 1280px) { .product-grid { grid-template-columns: repeat(4, 1fr); }}Why Mobile-First?
- Forces prioritization: Start with essential content
- Progressive enhancement: Add features for capable devices
- Smaller base CSS: Mobile styles are simpler
- Better performance: Less CSS to parse on mobile
Common Breakpoints
Establish consistent breakpoints as CSS variables:
:root { --breakpoint-sm: 640px; --breakpoint-md: 768px; --breakpoint-lg: 1024px; --breakpoint-xl: 1280px; --breakpoint-2xl: 1536px;}Unfortunately, CSS custom properties don’t work in media queries, so define them as comments or in documentation:
/* Breakpoints: sm: 640px - Large phones md: 768px - Tablets lg: 1024px - Small desktops xl: 1280px - Large desktops 2xl: 1536px - Extra large screens*/Fluid Typography
Scale text smoothly between breakpoints using clamp():
:root { /* Min size, preferred size, max size */ --font-size-base: clamp(1rem, 0.95rem + 0.25vw, 1.125rem); --font-size-lg: clamp(1.125rem, 1rem + 0.5vw, 1.5rem); --font-size-xl: clamp(1.5rem, 1.25rem + 1vw, 2.5rem); --font-size-2xl: clamp(2rem, 1.5rem + 2vw, 4rem);}
h1 { font-size: var(--font-size-2xl);}
h2 { font-size: var(--font-size-xl);}
p { font-size: var(--font-size-base);}Fluid Spacing
Apply the same principle to spacing:
:root { --spacing-section: clamp(2rem, 5vw, 5rem); --spacing-container: clamp(1rem, 3vw, 2rem);}
.section { padding-top: var(--spacing-section); padding-bottom: var(--spacing-section);}
.container { padding-left: var(--spacing-container); padding-right: var(--spacing-container);}Responsive Grid Patterns
Auto-Fit Grid
Let the browser decide how many columns fit:
.product-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--spacing-md);}This creates as many 250px+ columns as will fit.
Auto-Fill vs Auto-Fit
/* auto-fill: Empty tracks remain */grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* auto-fit: Empty tracks collapse */grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));Use auto-fit when you want items to stretch to fill space.
Responsive Column Count
For controlled column counts with section settings:
<style> .product-grid--{{ section.id }} { --columns-mobile: {{ section.settings.columns_mobile }}; --columns-tablet: {{ section.settings.columns_tablet }}; --columns-desktop: {{ section.settings.columns_desktop }}; }</style>.product-grid { display: grid; grid-template-columns: repeat(var(--columns-mobile, 1), 1fr); gap: var(--spacing-md);}
@media (min-width: 768px) { .product-grid { grid-template-columns: repeat(var(--columns-tablet, 2), 1fr); }}
@media (min-width: 1024px) { .product-grid { grid-template-columns: repeat(var(--columns-desktop, 4), 1fr); }}Flexbox Responsive Patterns
Wrapping Navigation
.nav-list { display: flex; flex-wrap: wrap; gap: var(--spacing-sm);}
.nav-link { padding: var(--spacing-xs) var(--spacing-sm);}Stack to Row
.feature-block { display: flex; flex-direction: column; gap: var(--spacing-md);}
@media (min-width: 768px) { .feature-block { flex-direction: row; align-items: center; }
.feature-block__media, .feature-block__content { flex: 1; }}Centered Content with Max-Width
.hero-content { display: flex; flex-direction: column; align-items: center; text-align: center; max-width: 600px; margin: 0 auto; padding: var(--spacing-lg);}Container Queries
For component-based responsive design (modern browsers):
.product-card-wrapper { container-type: inline-size;}
.product-card { display: flex; flex-direction: column;}
@container (min-width: 400px) { .product-card { flex-direction: row; }
.product-card__media { width: 40%; }}Container queries let components respond to their container’s size rather than the viewport.
Responsive Images
Aspect Ratio Boxes
Maintain consistent image ratios:
.product-card__media { aspect-ratio: 3 / 4; overflow: hidden;}
.product-card__image { width: 100%; height: 100%; object-fit: cover;}Responsive Background Images
<style> .hero-banner { background-image: url('{{ section.settings.image | image_url: width: 800 }}'); }
@media (min-width: 768px) { .hero-banner { background-image: url('{{ section.settings.image | image_url: width: 1200 }}'); } }
@media (min-width: 1280px) { .hero-banner { background-image: url('{{ section.settings.image | image_url: width: 1920 }}'); } }</style>Picture Element for Art Direction
<picture> <source media="(min-width: 1024px)" srcset="{{ section.settings.image_desktop | image_url: width: 1920 }}" > <source media="(min-width: 640px)" srcset="{{ section.settings.image_tablet | image_url: width: 1024 }}" > <img src="{{ section.settings.image_mobile | image_url: width: 640 }}" alt="{{ section.settings.image_alt }}" loading="lazy" ></picture>Responsive Tables
Tables are notoriously difficult on mobile:
/* Stack table on mobile */@media (max-width: 767px) { .responsive-table thead { display: none; }
.responsive-table tr { display: block; margin-bottom: var(--spacing-md); border: 1px solid var(--color-border); }
.responsive-table td { display: flex; justify-content: space-between; padding: var(--spacing-sm); border-bottom: 1px solid var(--color-border); }
.responsive-table td::before { content: attr(data-label); font-weight: 600; }}<table class="responsive-table"> <thead> <tr> <th>Product</th> <th>Price</th> <th>Quantity</th> </tr> </thead> <tbody> <tr> <td data-label="Product">T-Shirt</td> <td data-label="Price">$29.99</td> <td data-label="Quantity">2</td> </tr> </tbody></table>Hide/Show Based on Breakpoint
.mobile-only { display: block;}
.desktop-only { display: none;}
@media (min-width: 1024px) { .mobile-only { display: none; }
.desktop-only { display: block; }}Use sparingly. Prefer responsive layouts over hiding/showing different markup.
Complete Responsive Section
/* Hero Banner Section */.hero-banner { display: flex; flex-direction: column; min-height: 60vh; padding: var(--spacing-xl) var(--spacing-md); background-size: cover; background-position: center;}
.hero-banner__content { display: flex; flex-direction: column; align-items: flex-start; gap: var(--spacing-md); max-width: 100%;}
.hero-banner__heading { font-size: var(--font-size-2xl); line-height: 1.1;}
.hero-banner__text { font-size: var(--font-size-lg); max-width: 40ch;}
.hero-banner__buttons { display: flex; flex-direction: column; gap: var(--spacing-sm); width: 100%;}
/* Tablet */@media (min-width: 768px) { .hero-banner { min-height: 70vh; padding: var(--spacing-2xl); }
.hero-banner__buttons { flex-direction: row; width: auto; }}
/* Desktop */@media (min-width: 1024px) { .hero-banner { min-height: 80vh; justify-content: center; }
.hero-banner__content { max-width: 50%; }}
/* Alignment variations */.hero-banner--center .hero-banner__content { align-items: center; text-align: center; margin: 0 auto;}
.hero-banner--right .hero-banner__content { margin-left: auto;}
@media (min-width: 1024px) { .hero-banner--right .hero-banner__content { align-items: flex-end; text-align: right; }}Testing Responsive Designs
Browser DevTools
- Open DevTools (F12)
- Click the device toggle icon
- Test at various widths
- Use device presets
Key Widths to Test
- 320px: Small phones (iPhone SE)
- 375px: Standard phones (iPhone 12/13)
- 414px: Large phones (iPhone Plus/Max)
- 768px: Tablets (iPad)
- 1024px: Small laptops
- 1280px: Standard desktops
- 1920px: Large monitors
Check for Issues
- Text overflow or cramping
- Tap targets too small (minimum 44px)
- Horizontal scrolling (almost never wanted)
- Images too large for container
- Font sizes readable without zoom
Practice Exercise
Create a responsive feature grid that:
- Shows 1 column on mobile
- Shows 2 columns on tablet
- Shows 4 columns on desktop
- Has consistent spacing that scales
.feature-grid { display: grid; grid-template-columns: 1fr; gap: clamp(1rem, 3vw, 2rem); padding: clamp(1rem, 5vw, 3rem);}
@media (min-width: 640px) { .feature-grid { grid-template-columns: repeat(2, 1fr); }}
@media (min-width: 1024px) { .feature-grid { grid-template-columns: repeat(4, 1fr); }}
.feature-item { display: flex; flex-direction: column; align-items: center; text-align: center; padding: var(--spacing-md);}
.feature-item__icon { font-size: clamp(2rem, 5vw, 3rem); margin-bottom: var(--spacing-sm);}
.feature-item__title { font-size: var(--font-size-lg); margin-bottom: var(--spacing-xs);}
.feature-item__text { font-size: var(--font-size-base); color: var(--color-text-light);}Key Takeaways
- Start mobile-first and add complexity upward
- Use fluid values with
clamp()for smooth scaling - Leverage CSS Grid with
auto-fitfor flexible layouts - Set consistent breakpoints across your theme
- Maintain aspect ratios for images
- Test at multiple widths, not just device presets
- Prefer responsive layouts over hiding/showing content
- Consider container queries for component-level responsiveness
What’s Next?
With responsive layouts mastered, the next lesson covers JavaScript Patterns: Progressive Enhancement for adding interactivity that works for everyone.
Finished this lesson?
Mark it complete to track your progress.
Discussion
Loading comments...