Assets: CSS, JS, and Front-End Architecture Intermediate 10 min read

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?

  1. Forces prioritization: Start with essential content
  2. Progressive enhancement: Add features for capable devices
  3. Smaller base CSS: Mobile styles are simpler
  4. 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

  1. Open DevTools (F12)
  2. Click the device toggle icon
  3. Test at various widths
  4. 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:

  1. Shows 1 column on mobile
  2. Shows 2 columns on tablet
  3. Shows 4 columns on desktop
  4. 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

  1. Start mobile-first and add complexity upward
  2. Use fluid values with clamp() for smooth scaling
  3. Leverage CSS Grid with auto-fit for flexible layouts
  4. Set consistent breakpoints across your theme
  5. Maintain aspect ratios for images
  6. Test at multiple widths, not just device presets
  7. Prefer responsive layouts over hiding/showing content
  8. 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...