.agents/skills/responsive-design/SKILL.md
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.
npx skillsauth add sidjamyl/GAMES-JTI- responsive-designInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Master modern responsive design techniques to create interfaces that adapt seamlessly across all screen sizes and device contexts.
/* Mobile-first breakpoints */
/* Base: Mobile (< 640px) */
@media (min-width: 640px) {
/* sm: Landscape phones, small tablets */
}
@media (min-width: 768px) {
/* md: Tablets */
}
@media (min-width: 1024px) {
/* lg: Laptops, small desktops */
}
@media (min-width: 1280px) {
/* xl: Desktops */
}
@media (min-width: 1536px) {
/* 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) */
/* 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: 200px 1fr;
gap: 1rem;
}
.card-image {
aspect-ratio: 1;
}
}
@container card (min-width: 600px) {
.card {
grid-template-columns: 250px 1fr;
}
.card-title {
font-size: 1.5rem;
}
}
/* Container query units */
.card-title {
/* 5% of container width, clamped between 1rem and 2rem */
font-size: clamp(1rem, 5cqi, 2rem);
}
// 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={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>
);
}
/* Fluid type scale using clamp() */
:root {
/* Min size, preferred (fluid), max size */
--text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--text-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);
--text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--text-lg: clamp(1.125rem, 1rem + 0.625vw, 1.25rem);
--text-xl: clamp(1.25rem, 1rem + 1.25vw, 1.5rem);
--text-2xl: clamp(1.5rem, 1.25rem + 1.25vw, 2rem);
--text-3xl: clamp(1.875rem, 1.5rem + 1.875vw, 2.5rem);
--text-4xl: clamp(2.25rem, 1.75rem + 2.5vw, 3.5rem);
}
/* 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.25rem, 0.2rem + 0.25vw, 0.5rem);
--space-sm: clamp(0.5rem, 0.4rem + 0.5vw, 0.75rem);
--space-md: clamp(1rem, 0.8rem + 1vw, 1.5rem);
--space-lg: clamp(1.5rem, 1.2rem + 1.5vw, 2.5rem);
--space-xl: clamp(2rem, 1.5rem + 2.5vw, 4rem);
}
// Utility function for fluid values
function fluidValue(
minSize: number,
maxSize: number,
minWidth = 320,
maxWidth = 1280,
) {
const slope = (maxSize - minSize) / (maxWidth - 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),
};
/* Auto-fit grid - items wrap automatically */
.grid-auto {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
gap: 1.5rem;
}
/* Auto-fill grid - maintains empty columns */
.grid-auto-fill {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
/* Responsive grid with named areas */
.page-layout {
display: grid;
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
gap: 1rem;
}
@media (min-width: 768px) {
.page-layout {
grid-template-columns: 1fr 300px;
grid-template-areas:
"header header"
"main sidebar"
"footer footer";
}
}
@media (min-width: 1024px) {
.page-layout {
grid-template-columns: 250px 1fr 300px;
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;
}
// 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))`,
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>
);
}
function ResponsiveNav({ items }) {
const [isOpen, setIsOpen] = useState(false);
return (
<nav className="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>
);
}
// 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"
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"
/>
);
}
// Responsive table with horizontal scroll
function ResponsiveTable({ data, columns }) {
return (
<div className="w-full overflow-x-auto">
<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>
</>
);
}
/* Standard viewport units */
.full-height {
height: 100vh; /* May cause issues on mobile */
}
/* Dynamic viewport units (recommended for mobile) */
.full-height-dynamic {
height: 100dvh; /* Accounts for mobile browser UI */
}
/* Small viewport (minimum) */
.min-full-height {
min-height: 100svh;
}
/* Large viewport (maximum) */
.max-full-height {
max-height: 100lvh;
}
/* Viewport-relative font sizing */
.hero-title {
/* 5vw with min/max bounds */
font-size: clamp(2rem, 5vw, 4rem);
}
development
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
development
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
tools
UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 9 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind, shadcn/ui). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient. Integrations: shadcn/ui MCP for component search and examples.
development
Three.js game development. Use for 3D web games, WebGL rendering, game mechanics, physics integration, character controllers, camera systems, lighting, animations, and interactive 3D experiences in the browser.