Agent Skills
Discover and share powerful Agent Skills for AI assistants
responsive-design - Agent Skill - Agent Skills
Home/ Skills / responsive-design Implement modern responsive layouts using container queries, fluid typography, CSS Grid, and mobile-first breakpoint strategies. Use when building adaptive interfaces, implementing fluid layouts, or creating component-level responsive behavior.
Use the skills CLI to install this skill with one command. Auto-detects all installed AI assistants.
Method 1 - skills CLI
npx skills i wshobson/agents/plugins/ui-design/skills/responsive-design CopyMethod 2 - openskills (supports sync & update)
npx openskills install wshobson/agents CopyAuto-detects Claude Code, Cursor, Codex CLI, Gemini CLI, and more. One install, works everywhere.
Installation Path
Download and extract to one of the following locations:
Claude Code Cursor OpenCode Gemini CLI Codex CLI
~/.claude/skills/responsive-design/ Back No setup needed. Let our cloud agents run this skill for you.
Select Model
Claude Haiku 4.5 $0.10 Claude Sonnet 4.5 $0.20 Claude Opus 4.5 $0.50 Claude Sonnet 4.5 $0.20 /task
Best for coding tasks
Try NowEnvironment setup included
Responsive Design
Master modern responsive design techniques to create interfaces that adapt seamlessly across all screen sizes and device contexts.
When to Use This Skill
Implementing mobile-first responsive layouts
Using container queries for component-based responsiveness
Creating fluid typography and spacing scales
Building complex layouts with CSS Grid and Flexbox
Designing breakpoint strategies for design systems
Implementing responsive images and media
Creating adaptive navigation patterns
Building responsive tables and data displays
Core Capabilities
1. Container Queries
Component-level responsiveness independent of viewport
Container query units (cqi, cqw, cqh)
Style queries for conditional styling
Fallbacks for browser support
2. Fluid Typography & Spacing
CSS clamp() for fluid scaling
Viewport-relative units (vw, vh, dvh)
Fluid type scales with min/max bounds
Responsive spacing systems
3. Layout Patterns
CSS Grid for 2D layouts
Flexbox for 1D distribution
Intrinsic layouts (content-based sizing)
Subgrid for nested grid alignment
4. Breakpoint Strategy
Mobile-first media queries
Content-based breakpoints
Design token integration
Feature queries (@supports)
Quick Reference
Modern Breakpoint Scale
/* Mobile-first breakpoints */
/* Base: Mobile (< 640px) */
@media ( min-width : 640 px ) {
/* sm: Landscape phones, small tablets */
}
@media ( min-width : 768 px ) {
/* md: Tablets */
}
@media ( min-width : 1024 px ) {
/* lg: Laptops, small desktops */
Key Patterns
Pattern 1: Container Queries
/* Define a containment context */
.card-container {
container-type : inline-size;
container-name : card;
}
/* Query the container, not the viewport */
@container card (min-width: 400px) {
.card {
display : grid ;
grid-template-columns : 200 px 1 fr ;
gap :
// React component with container queries
function ResponsiveCard ({ title , image , description }) {
return (
< div className = "@container" >
< article className = "flex flex-col @md:flex-row @md:gap-4" >
< img
src =
Pattern 2: Fluid Typography
/* Fluid type scale using clamp() */
:root {
/* Min size, preferred (fluid), max size */
--text-xs : clamp ( 0.75 rem , 0.7 rem + 0.25 vw , 0.875 rem );
--text-sm : clamp ( 0.875
// Utility function for fluid values
function fluidValue (
minSize : number ,
maxSize : number ,
minWidth = 320 ,
maxWidth = 1280 ,
) {
const slope = (maxSize - minSize) / (maxWidth -
Pattern 3: CSS Grid Responsive Layout
/* Auto-fit grid - items wrap automatically */
.grid-auto {
display : grid ;
grid-template-columns : repeat ( auto-fit , minmax ( min ( 300 px , 100 % ), 1 fr
// Responsive grid component
function ResponsiveGrid ({ children , minItemWidth = "250px" , gap = "1.5rem" }) {
return (
< div
className = "grid"
style = {{
gridTemplateColumns: `repeat(auto-fit, minmax(min(${ minItemWidth }, 100%), 1fr))` ,
Pattern 4: Responsive Navigation
function ResponsiveNav ({ items }) {
const [ isOpen , setIsOpen ] = useState ( false );
return (
< nav className
Pattern 5: Responsive Images
// Responsive image with art direction
function ResponsiveHero () {
return (
< picture >
{ /* Art direction: different crops for different screens */ }
< source
media = "(min-width: 1024px)"
srcSet = "/hero-wide.webp"
Pattern 6: Responsive Tables
// Responsive table with horizontal scroll
function ResponsiveTable ({ data , columns }) {
return (
< div className = "w-full overflow-x-auto" >
<
Viewport Units
/* Standard viewport units */
.full-height {
height : 100 vh ; /* May cause issues on mobile */
}
/* Dynamic viewport units (recommended for mobile) */
.full-height-dynamic {
height : 100 dvh ; /* Accounts for mobile browser UI */
}
/* Small viewport (minimum) */
.min-full-height {
min-height : 100 svh
Best Practices
Mobile-First : Start with mobile styles, enhance for larger screens
Content Breakpoints : Set breakpoints based on content, not devices
Fluid Over Fixed : Use fluid values for typography and spacing
Container Queries : Use for component-level responsiveness
Test Real Devices : Simulators don't catch all issues
Performance : Optimize images, lazy load off-screen content
Touch Targets : Maintain 44x44px minimum on mobile
Logical Properties : Use inline/block for internationalization
Common Issues
Horizontal Overflow : Content breaking out of viewport
Fixed Widths : Using px instead of relative units
Viewport Height : 100vh issues on mobile browsers
Font Size : Text too small on mobile
Touch Targets : Buttons too small to tap accurately
Aspect Ratio : Images squishing or stretching
Z-Index Stacking : Overlays breaking on different screens
Resources
}
@media ( min-width : 1280 px ) {
/* xl: Desktops */
}
@media ( min-width : 1536 px ) {
/* 2xl: Large desktops */
}
/* Tailwind CSS equivalent */
/* sm: @media (min-width: 640px) */
/* md: @media (min-width: 768px) */
/* lg: @media (min-width: 1024px) */
/* xl: @media (min-width: 1280px) */
/* 2xl: @media (min-width: 1536px) */
1
rem
;
}
.card-image {
aspect-ratio : 1 ;
}
}
@container card (min-width: 600px) {
.card {
grid-template-columns : 250 px 1 fr ;
}
.card-title {
font-size : 1.5 rem ;
}
}
/* Container query units */
.card-title {
/* 5% of container width, clamped between 1rem and 2rem */
font-size : clamp ( 1 rem , 5 cqi , 2 rem );
}
{image}
alt = ""
className = "w-full @md:w-48 @lg:w-64 aspect-video @md:aspect-square object-cover"
/>
< div className = "p-4 @md:p-0" >
< h2 className = "text-lg @md:text-xl @lg:text-2xl font-semibold" >
{title}
</ h2 >
< p className = "mt-2 text-muted-foreground @md:line-clamp-3" >
{description}
</ p >
</ div >
</ article >
</ div >
);
}
rem
,
0.8
rem
+
0.375
vw
,
1
rem
);
--text-base : clamp ( 1 rem , 0.9 rem + 0.5 vw , 1.125 rem );
--text-lg : clamp ( 1.125 rem , 1 rem + 0.625 vw , 1.25 rem );
--text-xl : clamp ( 1.25 rem , 1 rem + 1.25 vw , 1.5 rem );
--text-2xl : clamp ( 1.5 rem , 1.25 rem + 1.25 vw , 2 rem );
--text-3xl : clamp ( 1.875 rem , 1.5 rem + 1.875 vw , 2.5 rem );
--text-4xl : clamp ( 2.25 rem , 1.75 rem + 2.5 vw , 3.5 rem );
}
/* Usage */
h1 {
font-size : var ( --text-4xl );
}
h2 {
font-size : var ( --text-3xl );
}
h3 {
font-size : var ( --text-2xl );
}
p {
font-size : var ( --text-base );
}
/* Fluid spacing scale */
:root {
--space-xs : clamp ( 0.25 rem , 0.2 rem + 0.25 vw , 0.5 rem );
--space-sm : clamp ( 0.5 rem , 0.4 rem + 0.5 vw , 0.75 rem );
--space-md : clamp ( 1 rem , 0.8 rem + 1 vw , 1.5 rem );
--space-lg : clamp ( 1.5 rem , 1.2 rem + 1.5 vw , 2.5 rem );
--space-xl : clamp ( 2 rem , 1.5 rem + 2.5 vw , 4 rem );
}
minWidth);
const yAxisIntersection = - minWidth * slope + minSize;
return `clamp(${ minSize }rem, ${ yAxisIntersection . toFixed ( 4 ) }rem + ${ ( slope * 100 ). toFixed ( 4 ) }vw, ${ maxSize }rem)` ;
}
// Generate fluid type scale
const fluidTypeScale = {
sm: fluidValue ( 0.875 , 1 ),
base: fluidValue ( 1 , 1.125 ),
lg: fluidValue ( 1.25 , 1.5 ),
xl: fluidValue ( 1.5 , 2 ),
"2xl" : fluidValue ( 2 , 3 ),
};
));
gap : 1.5 rem ;
}
/* Auto-fill grid - maintains empty columns */
.grid-auto-fill {
display : grid ;
grid-template-columns : repeat ( auto-fill , minmax ( 250 px , 1 fr ));
gap : 1 rem ;
}
/* Responsive grid with named areas */
.page-layout {
display : grid ;
grid-template-areas :
"header"
"main"
"sidebar"
"footer" ;
gap : 1 rem ;
}
@media ( min-width : 768 px ) {
.page-layout {
grid-template-columns : 1 fr 300 px ;
grid-template-areas :
"header header"
"main sidebar"
"footer footer" ;
}
}
@media ( min-width : 1024 px ) {
.page-layout {
grid-template-columns : 250 px 1 fr 300 px ;
grid-template-areas :
"header header header"
"nav main sidebar"
"footer footer footer" ;
}
}
.header {
grid-area : header;
}
.main {
grid-area : main;
}
.sidebar {
grid-area : sidebar;
}
.footer {
grid-area : footer;
}
gap,
}}
>
{children}
</ div >
);
}
// Usage with Tailwind
function ProductGrid ({ products }) {
return (
< div className = "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 md:gap-6" >
{products. map (( product ) => (
< ProductCard key = {product.id} product = {product} />
))}
</ div >
);
}
=
"relative"
>
{ /* Mobile menu button */ }
< button
className = "lg:hidden p-2"
onClick = {() => setIsOpen ( ! isOpen)}
aria-expanded = {isOpen}
aria-controls = "nav-menu"
>
< span className = "sr-only" >Toggle navigation</ span >
{isOpen ? < X /> : < Menu />}
</ button >
{ /* Navigation links */ }
< ul
id = "nav-menu"
className = { cn (
// Base: hidden on mobile
"absolute top-full left-0 right-0 bg-background border-b" ,
"flex flex-col" ,
// Mobile: slide down
isOpen ? "flex" : "hidden" ,
// Desktop: always visible, horizontal
"lg:static lg:flex lg:flex-row lg:border-0 lg:bg-transparent" ,
)}
>
{items. map (( item ) => (
< li key = {item.href}>
< a
href = {item.href}
className = { cn (
"block px-4 py-3" ,
"lg:px-3 lg:py-2" ,
"hover:bg-muted lg:hover:bg-transparent lg:hover:text-primary" ,
)}
>
{item.label}
</ a >
</ li >
))}
</ ul >
</ nav >
);
}
type = "image/webp"
/>
< source
media = "(min-width: 768px)"
srcSet = "/hero-medium.webp"
type = "image/webp"
/>
< source srcSet = "/hero-mobile.webp" type = "image/webp" />
{ /* Fallback */ }
< img
src = "/hero-mobile.jpg"
alt = "Hero image description"
className = "w-full h-auto"
loading = "eager"
fetchpriority = "high"
/>
</ picture >
);
}
// Responsive image with srcset for resolution switching
function ProductImage ({ product }) {
return (
< img
src = {product.image}
srcSet = { `
${ product . image }?w=400 400w,
${ product . image }?w=800 800w,
${ product . image }?w=1200 1200w
` }
sizes = "(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
alt = {product.name}
className = "w-full h-auto object-cover"
loading = "lazy"
/>
);
}
table
className
=
"w-full min-w-[600px]"
>
< thead >
< tr >
{columns. map (( col ) => (
< th key = {col.key} className = "text-left p-3" >
{col.label}
</ th >
))}
</ tr >
</ thead >
< tbody >
{data. map (( row , i ) => (
< tr key = {i} className = "border-t" >
{columns. map (( col ) => (
< td key = {col.key} className = "p-3" >
{row[col.key]}
</ td >
))}
</ tr >
))}
</ tbody >
</ table >
</ div >
);
}
// Card-based table for mobile
function ResponsiveDataTable ({ data , columns }) {
return (
<>
{ /* Desktop table */ }
< table className = "hidden md:table w-full" >
{ /* ... standard table */ }
</ table >
{ /* Mobile cards */ }
< div className = "md:hidden space-y-4" >
{data. map (( row , i ) => (
< div key = {i} className = "border rounded-lg p-4 space-y-2" >
{columns. map (( col ) => (
< div key = {col.key} className = "flex justify-between" >
< span className = "font-medium text-muted-foreground" >
{col.label}
</ span >
< span >{row[col.key]}</ span >
</ div >
))}
</ div >
))}
</ div >
</>
);
}
;
}
/* Large viewport (maximum) */
.max-full-height {
max-height : 100 lvh ;
}
/* Viewport-relative font sizing */
.hero-title {
/* 5vw with min/max bounds */
font-size : clamp ( 2 rem , 5 vw , 4 rem );
}