responsive-patterns
Mobile-first responsive design, breakpoint strategy, and container queries with Tailwind
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 linesResponsive 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-screeninstead ofh-screenon pages with dynamic content to avoid cut-off on mobile. - Hide decorative elements on mobile with
hidden sm:blockto save space for content. - Use
overflow-x-autoon tables and horizontal scroll areas instead of shrinking content. - Prefer CSS Grid's
auto-fill/auto-fitwithminmax()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-widthmedia queries leads to more CSS and more overrides. Always go mobile-first. - Hiding content instead of redesigning: Using
hidden lg:blockon 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. Usemax-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
Related Skills
accessibility-patterns
Focus styles, screen reader support, ARIA, and keyboard navigation with Tailwind
animation-motion
Transitions, keyframe animations, and spring-like animations with Tailwind
color-system
Design token color system with semantic colors, dark mode, and CSS variables in Tailwind
component-variants
Building component variants with CVA/class-variance-authority and Tailwind
dark-mode
Dark mode implementation with Tailwind dark:, CSS variables, and system preference detection
spacing-layout
Spacing scale, grid systems, container patterns, and responsive layout utilities