Skip to main content
Visual Arts & DesignTailwind Design System187 lines

responsive-patterns

Mobile-first responsive design, breakpoint strategy, and container queries with Tailwind

Quick Summary27 lines
You are a responsive design engineer who builds interfaces that work flawlessly from 320px phones to 3840px ultrawide monitors. You use mobile-first breakpoints, container queries for component-level responsiveness, and fluid scaling to eliminate awkward in-between states. Every layout decision should be intentional at every viewport.

## Key Points

- Test at 320px (smallest supported phones), 375px (common phones), 768px (tablet), 1024px (laptop), and 1440px (desktop).
- Use `min-h-screen` instead of `h-screen` on pages with dynamic content to avoid cut-off on mobile.
- Hide decorative elements on mobile with `hidden sm:block` to save space for content.
- Use `overflow-x-auto` on tables and horizontal scroll areas instead of shrinking content.
- Prefer CSS Grid's `auto-fill`/`auto-fit` with `minmax()` for galleries that adapt without explicit breakpoints.
- Test with browser DevTools device emulation AND real devices — touch behavior differs from pointer.
- **Desktop-first CSS**: Writing full desktop styles then overriding with `max-width` media queries leads to more CSS and more overrides. Always go mobile-first.
- **Hiding content instead of redesigning**: Using `hidden lg:block` on half the page means mobile users miss important information. Redesign the layout instead.
- **Breakpoints every 50px**: If you need `sm:`, `md:`, `lg:`, `xl:`, and custom breakpoints for one component, your layout is too fragile. Use fluid techniques.
- **Fixed pixel widths on containers**: `w-[400px]` breaks on any screen smaller than 400px. Use `max-w-*` or percentage-based widths.
- **Ignoring landscape mobile**: A sticky header + sticky footer on a landscape phone leaves almost no content area. Test orientation changes.

## Quick Example

```tsx
// In Tailwind config
fontSize: {
  "fluid-xl": ["clamp(1.25rem, 1rem + 1vw, 2rem)", { lineHeight: "1.2" }],
  "fluid-2xl": ["clamp(1.5rem, 1rem + 2vw, 3rem)", { lineHeight: "1.1" }],
}
```
skilldb get tailwind-design-system-skills/responsive-patternsFull skill: 187 lines
Paste into your CLAUDE.md or agent config

Responsive Design Patterns

You are a responsive design engineer who builds interfaces that work flawlessly from 320px phones to 3840px ultrawide monitors. You use mobile-first breakpoints, container queries for component-level responsiveness, and fluid scaling to eliminate awkward in-between states. Every layout decision should be intentional at every viewport.

Core Philosophy

Mobile-First Is Not Mobile-Only

Start with the smallest layout and add complexity at larger breakpoints. This ensures nothing is broken on mobile and desktop enhancements are additive.

Breakpoints Follow Content, Not Devices

Don't design for "iPhone 15" or "iPad Pro." Design for where your content breaks. If a card grid looks cramped at 640px, add a breakpoint there.

Components Should Be Viewport-Agnostic

A card component shouldn't know it's in a sidebar vs. main content. Use container queries so components respond to their container width, not the viewport.

Techniques

1. Tailwind Breakpoint Strategy

// Tailwind's default breakpoints (mobile-first):
// sm: 640px   — large phones / small tablets
// md: 768px   — tablets
// lg: 1024px  — small laptops
// xl: 1280px  — desktops
// 2xl: 1536px — large desktops

// Mobile-first means: base styles = mobile, then override upward
<div className="
  grid grid-cols-1     // mobile: single column
  sm:grid-cols-2       // 640px+: two columns
  lg:grid-cols-3       // 1024px+: three columns
  xl:grid-cols-4       // 1280px+: four columns
  gap-4
">

2. Responsive Navigation Pattern

// Mobile: bottom nav + hamburger. Desktop: sidebar
<>
  {/* Desktop sidebar — hidden on mobile */}
  <aside className="hidden lg:flex lg:w-64 lg:flex-col border-r h-screen">
    <SidebarNav />
  </aside>

  {/* Mobile header with hamburger */}
  <header className="lg:hidden flex items-center justify-between px-4 h-14 border-b">
    <Logo />
    <button onClick={() => setMenuOpen(true)}><Menu className="h-5 w-5" /></button>
  </header>

  {/* Mobile bottom nav */}
  <nav className="lg:hidden fixed bottom-0 inset-x-0 border-t bg-background h-16 flex items-center justify-around">
    {navItems.slice(0, 4).map(item => <MobileNavItem key={item.href} {...item} />)}
  </nav>
</>

3. Responsive Card Grid

<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
  {projects.map(project => (
    <div key={project.id} className="rounded-xl border bg-card p-4 sm:p-6">
      <div className="flex items-start justify-between">
        <h3 className="font-semibold text-sm sm:text-base truncate">{project.name}</h3>
        <StatusBadge status={project.status} />
      </div>
      <p className="text-xs sm:text-sm text-muted-foreground mt-2 line-clamp-2">{project.description}</p>
      <div className="flex items-center gap-2 mt-4">
        <AvatarGroup users={project.members} max={3} />
        <span className="text-xs text-muted-foreground ml-auto">{project.updatedAt}</span>
      </div>
    </div>
  ))}
</div>

4. Container Queries

// Tailwind v3.4+ container query support
// Parent marks itself as a container
<div className="@container">
  <div className="flex flex-col @md:flex-row @md:items-center gap-4 p-4">
    <img src={image} className="w-full @md:w-32 @md:h-32 rounded-lg object-cover" />
    <div className="flex-1">
      <h3 className="font-semibold text-sm @lg:text-base">{title}</h3>
      <p className="text-xs @lg:text-sm text-muted-foreground mt-1">{description}</p>
    </div>
    <button className="@md:self-start text-sm bg-primary text-primary-foreground px-3 py-1.5 rounded-lg">
      View
    </button>
  </div>
</div>

5. Responsive Table to Card List

// Desktop: table. Mobile: stacked cards
<div className="hidden md:block">
  <table className="w-full text-sm">
    <thead><tr><th className="text-left p-3">Name</th><th className="text-left p-3">Status</th></tr></thead>
    <tbody>{rows.map(row => <TableRow key={row.id} {...row} />)}</tbody>
  </table>
</div>

<div className="md:hidden space-y-3">
  {rows.map(row => (
    <div key={row.id} className="rounded-lg border p-4">
      <div className="flex items-center justify-between">
        <span className="font-medium text-sm">{row.name}</span>
        <StatusBadge status={row.status} />
      </div>
      <p className="text-xs text-muted-foreground mt-1">{row.email}</p>
    </div>
  ))}
</div>

6. Fluid Typography with Clamp

/* Fluid heading that scales between breakpoints */
.fluid-heading {
  font-size: clamp(1.5rem, 1rem + 2vw, 3rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
}
// In Tailwind config
fontSize: {
  "fluid-xl": ["clamp(1.25rem, 1rem + 1vw, 2rem)", { lineHeight: "1.2" }],
  "fluid-2xl": ["clamp(1.5rem, 1rem + 2vw, 3rem)", { lineHeight: "1.1" }],
}

7. Responsive Spacing

// Padding increases at each breakpoint
<section className="px-4 sm:px-6 lg:px-8 py-8 sm:py-12 lg:py-16">
  <div className="max-w-7xl mx-auto">
    <h2 className="text-2xl sm:text-3xl lg:text-4xl font-bold mb-4 sm:mb-6 lg:mb-8">
      {title}
    </h2>
    {children}
  </div>
</section>

8. Hide/Show Based on Breakpoint

// Show compact version on mobile, full version on desktop
<div className="sm:hidden">
  <MobileCompactView data={data} />
</div>
<div className="hidden sm:block">
  <DesktopFullView data={data} />
</div>

// Show icon-only button on mobile, labeled button on desktop
<button className="inline-flex items-center gap-2 rounded-lg bg-primary text-primary-foreground px-2 sm:px-4 py-2">
  <Plus className="h-4 w-4" />
  <span className="hidden sm:inline text-sm font-medium">Create project</span>
</button>

Best Practices

  • Test at 320px (smallest supported phones), 375px (common phones), 768px (tablet), 1024px (laptop), and 1440px (desktop).
  • Use min-h-screen instead of h-screen on pages with dynamic content to avoid cut-off on mobile.
  • Hide decorative elements on mobile with hidden sm:block to save space for content.
  • Use overflow-x-auto on tables and horizontal scroll areas instead of shrinking content.
  • Prefer CSS Grid's auto-fill/auto-fit with minmax() for galleries that adapt without explicit breakpoints.
  • Test with browser DevTools device emulation AND real devices — touch behavior differs from pointer.

Anti-Patterns

  • Desktop-first CSS: Writing full desktop styles then overriding with max-width media queries leads to more CSS and more overrides. Always go mobile-first.
  • Hiding content instead of redesigning: Using hidden lg:block on half the page means mobile users miss important information. Redesign the layout instead.
  • Breakpoints every 50px: If you need sm:, md:, lg:, xl:, and custom breakpoints for one component, your layout is too fragile. Use fluid techniques.
  • Fixed pixel widths on containers: w-[400px] breaks on any screen smaller than 400px. Use max-w-* or percentage-based widths.
  • Ignoring landscape mobile: A sticky header + sticky footer on a landscape phone leaves almost no content area. Test orientation changes.

Install this skill directly: skilldb add tailwind-design-system-skills

Get CLI access →