Get the FREE Ultimate OpenClaw Setup Guide →
w

Responsive Design

Verified

@wpank

npx machina-cli add skill @wpank/responsive-design --openclaw
Files (1)
SKILL.md
10.1 KB

Responsive Design

Modern responsive CSS patterns using container queries, fluid typography, CSS Grid, and mobile-first strategies.

WHAT

Comprehensive responsive design techniques:

  • Container queries for component-level responsiveness
  • Fluid typography and spacing with clamp()
  • CSS Grid and Flexbox layout patterns
  • Mobile-first breakpoint strategies
  • Responsive images and media
  • Viewport units and dynamic sizing

WHEN

  • Building layouts that adapt across screen sizes
  • Creating reusable components that respond to container size
  • Implementing fluid typography scales
  • Setting up responsive grid systems
  • Handling mobile navigation patterns
  • Optimizing images for different devices

KEYWORDS

responsive, container query, media query, breakpoint, mobile-first, fluid typography, clamp, css grid, flexbox, viewport, adaptive, responsive images

Installation

OpenClaw / Moltbot / Clawbot

npx clawhub@latest install responsive-design

Breakpoint Scale (Mobile-First)

/* Base: Mobile (< 640px) - no media query needed */

@media (min-width: 640px)  { /* sm: Large phones, small tablets */ }
@media (min-width: 768px)  { /* md: Tablets */ }
@media (min-width: 1024px) { /* lg: Laptops */ }
@media (min-width: 1280px) { /* xl: Desktops */ }
@media (min-width: 1536px) { /* 2xl: Large screens */ }

Tailwind equivalents: sm:, md:, lg:, xl:, 2xl:


Container Queries

Component-level responsiveness independent of viewport:

/* Define containment context */
.card-container {
  container-type: inline-size;
  container-name: card;
}

/* Query the container, not viewport */
@container card (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 200px 1fr;
  }
}

@container card (min-width: 600px) {
  .card-title {
    font-size: 1.5rem;
  }
}

/* Container query units */
.card-title {
  font-size: clamp(1rem, 5cqi, 2rem); /* 5% of container inline-size */
}

Tailwind 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 Typography

CSS Custom Properties Scale

:root {
  --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);
}

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);
}

Clamp Formula

clamp(MIN, PREFERRED, MAX)

MIN: Smallest allowed size
PREFERRED: Ideal fluid calculation (often uses vw)
MAX: Largest allowed size

CSS Grid Responsive Layouts

Auto-Fit Grid (Items Wrap)

.grid-auto {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 1.5rem;
}

Named Grid 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; }

Tailwind Grid

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>
  )
}

Responsive Navigation

function ResponsiveNav({ items }) {
  const [isOpen, setIsOpen] = useState(false)

  return (
    <nav className="relative">
      {/* Mobile toggle */}
      <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(
          // Mobile: dropdown
          "absolute top-full left-0 right-0 bg-background border-b",
          "flex flex-col",
          isOpen ? "flex" : "hidden",
          // Desktop: horizontal, always visible
          "lg:static lg:flex lg:flex-row lg:border-0"
        )}
      >
        {items.map(item => (
          <li key={item.href}>
            <a
              href={item.href}
              className="block px-4 py-3 lg:px-3 lg:py-2 hover:bg-muted lg:hover:bg-transparent"
            >
              {item.label}
            </a>
          </li>
        ))}
      </ul>
    </nav>
  )
}

Responsive Images

Art Direction with Picture

function ResponsiveHero() {
  return (
    <picture>
      {/* 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" />
      
      <img
        src="/hero-mobile.jpg"
        alt="Hero description"
        className="w-full h-auto"
        loading="eager"
        fetchPriority="high"
      />
    </picture>
  )
}

Resolution Switching with srcset

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 Tables

Horizontal Scroll Pattern

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 Layout on Mobile

function ResponsiveDataTable({ data, columns }) {
  return (
    <>
      {/* Desktop: table */}
      <table className="hidden md:table w-full">
        {/* standard table markup */}
      </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>
    </>
  )
}

Viewport Units

/* Standard viewport units - problematic on mobile */
.full-height { height: 100vh; }

/* Dynamic viewport units (recommended) */
.full-height-dynamic { height: 100dvh; } /* Accounts for mobile browser UI */

/* Small viewport (minimum when UI shown) */
.min-full-height { min-height: 100svh; }

/* Large viewport (maximum when UI hidden) */
.max-full-height { max-height: 100lvh; }

Best Practices

  1. Mobile-First: Write base styles for mobile, enhance for larger screens
  2. Content Breakpoints: Set breakpoints where content breaks, not device sizes
  3. Fluid Over Fixed: Prefer clamp() and relative units over fixed px
  4. Container Queries: Use for component-level responsiveness
  5. Touch Targets: Minimum 44×44px tap targets on mobile
  6. Test Real Devices: Simulators don't catch all issues
  7. Logical Properties: Use inline/block for internationalization

Common Issues

IssueCauseFix
Horizontal scrollFixed widthsUse relative units, max-width: 100%
100vh too tall on mobileAddress barUse 100dvh or 100svh
Tiny tap targetsDesktop designMin 44px height/width on interactive elements
Images breaking layoutMissing constraintsAdd max-width: 100%; height: auto;
Text too smallFixed font sizeUse fluid typography with clamp()

NEVER

  • Use px for typography (use rem)
  • Skip mobile testing on real devices
  • Forget touch target sizing (44×44px minimum)
  • Use 100vh on mobile without fallback
  • Nest too many media queries (flattens readability)
  • Ignore content-based breakpoints in favor of device-specific ones

Source

git clone https://clawhub.ai/wpank/responsive-designView on GitHub

Overview

Responsive Design enables layouts that adapt across devices by combining container queries, fluid typography, CSS Grid, and mobile-first breakpoints. It also covers responsive images and adaptive navigation to deliver consistent experiences on phones, tablets, and desktops.

How This Skill Works

Technically, it uses container-type and @container queries to size components by their inline-size, while clamp()-driven typography and spacing scale with container and viewport changes. CSS Grid and Flexbox provide flexible layouts, and a mobile-first breakpoint strategy guides progressive enhancement. Responsive images and adaptive navigation patterns complete the experience.

When to Use It

  • Design layouts that must adapt across a range of screen sizes (phones to desktops).
  • Build reusable components that respond to their container size, not just the viewport.
  • Implement fluid typography scales for readability on every device.
  • Set up responsive grid systems that reflow with space constraints.
  • Handle mobile navigation patterns and optimize images for different devices.

Quick Start

  1. Step 1: npx clawhub@latest install responsive-design
  2. Step 2: Create a mobile-first layout and add container queries for components
  3. Step 3: Apply clamp() typography, CSS Grid, and responsive images, then test at multiple breakpoints

Best Practices

  • Start with a mobile-first baseline and progressively enhance for larger viewports.
  • Prefer container queries to drive component-level responsiveness rather than global breakpoints.
  • Use clamp() for font sizes and spacing to maintain consistent rhythm.
  • Design grids with auto-fit or auto-fill and minmax to reflow gracefully.
  • Optimize images with srcset and sizes, and test across devices for accessibility.

Example Use Cases

  • A product card grid that reflows from a compact mobile layout to a multi-column grid using container queries.
  • A dashboard where widgets resize and reposition with container-based rules.
  • An adaptive navigation that becomes a drawer on small screens and a horizontal menu on large screens.
  • An image gallery that serves different image resolutions via srcset while maintaining aspect ratios.
  • A typographically scaled blog layout using clamp-based font sizes and fluid spacing.

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers