Responsive Design skill for Codex

Layouts that hold at every width, not three. Codex builds mobile-first layouts with a small set of content-driven breakpoints, lets components respond to their own container, and prefers intrinsic grids and clamp() over extra media queries. Tables, navigation and hover-only controls get explicit small-screen treatments, and a Playwright sweep from 320 to 1920 px catches horizontal overflow and broken layouts between the usual device sizes.

  • Design & UX
  • $responsive-design
  • 197 lines
  • 2 files
  • ~1,800 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- responsive-design

Installs to ~/.agents/skills/responsive-design/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $responsive-design, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Plans and implements responsive layouts across phone, tablet, laptop and wide screens - content-driven breakpoints in rem, mobile-first min-width media queries, container queries for components, fluid type and spacing with clamp(), intrinsic grid layouts, responsive tables and navigation, input-capability queries, and WCAG 1.4.10 reflow at 320 CSS px. Verifies with Playwright screenshots at a width sweep. Use when a site breaks at certain widths, when defining a breakpoint strategy, or making a desktop-only UI work on small screens.

Use it when

  • Layouts break, overlap or scroll sideways at certain widths
  • A project has inconsistent or device-named breakpoints
  • A desktop-first UI must work on tablets and phones
  • You need to prove WCAG reflow at 320 CSS pixels

Use something else when

How to check the result

The Playwright width sweep reports zero horizontal overflow from 320 to 1920 px, and screenshots on either side of each breakpoint show no clipped or overlapping content.

The mistake it prevents

Testing only at 375, 768 and 1440, so the layout collapses at the widths in between that real windows and tablets use.

~/.agents/skills/responsive-design/SKILL.md

--- name: responsive-design description: Plans and implements responsive layouts across phone, tablet, laptop and wide screens - content-driven breakpoints in rem, mobile-first min-width… license: MIT ---

Responsive work is done when the layout holds at every width from 320 to 2560 CSS px, not just at the three device sizes in the mockup: no horizontal scroll, no overlapping or clipped content, readable line lengths, and the same tasks possible at every size.

Strategy

  • Mobile-first. Base styles are the narrow layout; min-width queries add columns. Narrow layouts are simpler, and overrides only ever add complexity in one direction.
  • Content decides breakpoints. Resize until the layout breaks (lines too long, cards too squeezed), then add a breakpoint there. Do not name breakpoints after devices.
  • Components respond to their container, pages to the viewport. A card in a sidebar and in a main column should adapt to its own width: container queries.
  • Intrinsic first. auto-fit/minmax, flex-wrap and clamp() often remove the need for a breakpoint entirely.

Inspect before changing

rg -n "@media|@container|screens:|breakpoints" --glob '!**/node_modules/**' | head -40
rg -n "100vw|width:\s*\d{3,}px|min-width:\s*\d{3,}px" --glob '*.{css,scss,tsx,jsx,vue,svelte}' | head

Read AGENTS.md, the Tailwind config or @theme block, and any breakpoint tokens. Reuse existing breakpoints; consolidate near-duplicates (767, 768, 770) instead of adding more.

Breakpoint scale

A small, content-driven default when the project has none:

TokenValueTypical change
sm40rem (640px)Two-up cards, inline form rows
md48rem (768px)Sidebar appears, tables leave card mode
lg64rem (1024px)Three columns, full navigation
xl80rem (1280px)Max content width reached; margins grow

Use rem so breakpoints scale with the user’s font-size setting. Range syntax is supported in all current browsers:

@media (width >= 48rem) { .layout { grid-template-columns: 16rem 1fr; } }

Core patterns

Intrinsic grid (often no media query needed)

.cards { display: grid; gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr)); }

min(18rem, 100%) prevents overflow on screens narrower than 18rem.

Page shell

.shell { display: grid; min-height: 100dvh; grid-template-rows: auto 1fr auto; }
.main  { width: min(100% - 2rem, 70rem); margin-inline: auto; }
@media (width >= 64rem) {
  .shell { grid-template-columns: 15rem 1fr; grid-template-rows: auto 1fr; }
  .sidebar { grid-row: 1 / -1; }
}

Container queries for components

.product-card-wrap { container: card / inline-size; }
.product-card { display: grid; gap: .75rem; }
@container card (width >= 28rem) {
  .product-card { grid-template-columns: 8rem 1fr; align-items: start; }
}

Tailwind v4 has container query variants built in (@container on the parent, @md: style variants on children); check the project’s version before using them.

Fluid type and space

:root {
  --step-0: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  --step-3: clamp(1.75rem, 1.4rem + 1.6vw, 2.75rem);
  --gutter: clamp(1rem, 0.5rem + 2.5vw, 3rem);
}

Always include a rem term in the preferred value so text still scales with browser zoom (pure vw text fails WCAG 1.4.4 resize text).

Readable measure

.prose { max-width: 68ch; }

Tables

DataSmall-screen treatment
Few columns, row = recordStack to cards with data-label headers
Many numeric columns compared across rowsHorizontal scroll inside a focusable wrapper with sticky first column
Many columns, few needed on mobilePriority columns; “Show columns” toggle
<div class="table-scroll" role="region" aria-label="Invoices" tabindex="0"><table>...</table></div>
.table-scroll { overflow-x: auto; }
.table-scroll th:first-child, .table-scroll td:first-child { position: sticky; left: 0; background: var(--surface); }

Under md: a menu button revealing a panel (a <dialog> or disclosure with aria-expanded), or a bottom tab bar for apps. Above: inline links. Keep the same items and order at all sizes; do not drop destinations on mobile.

Input capability, not screen size

@media (hover: hover) and (pointer: fine) { .row-actions { opacity: 0; } .row:hover .row-actions { opacity: 1; } }
@media (pointer: coarse) { .icon-btn { min-width: 44px; min-height: 44px; } }

Never hide functionality behind hover on touch devices; a tablet can be 1024px wide.

Gotchas

  • 100vw includes the vertical scrollbar on desktop and causes horizontal scroll; use 100% or dvw. Likewise prefer dvh/svh to vh on mobile.
  • A single long word, URL or code block overflows narrow containers: overflow-wrap: anywhere on user content, min-width: 0 on grid and flex children.
  • Images without max-width: 100%; height: auto and without width/height attributes overflow and cause layout shift. Responsive image sources: $responsive-images.
  • display: none at a breakpoint still loads that content’s images and scripts; for heavy components, render conditionally or lazy load.
  • Ordering with order or grid placement changes visual order but not tab order; keep DOM order logical.
  • Landscape phones (about 390-430px tall) break sticky headers plus sticky footers plus keyboard. Test one landscape case.

Verification: width sweep

Check reflow at 320 CSS px (WCAG 1.4.10: equivalent to 1280 at 400% zoom) and a sweep of widths. A Playwright script (needs @playwright/test installed; browsers download needs network):

// tests/responsive.spec.ts
import { test, expect } from "@playwright/test";
const widths = [320, 375, 414, 600, 768, 900, 1024, 1280, 1440, 1920];
for (const path of ["/", "/pricing", "/app/projects"]) {
  for (const w of widths) {
    test(`${path} @ ${w}`, async ({ page }) => {
      await page.setViewportSize({ width: w, height: 900 });
      await page.goto(path);
      const overflow = await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth);
      expect(overflow, "horizontal overflow").toBeLessThanOrEqual(0);
      await page.screenshot({ path: `shots/${path.replace(/\W+/g, "_")}-${w}.png`, fullPage: true });
    });
  }
}

Then look at the screenshots in order; the frames just before and after each breakpoint are where layouts break. Also test 200% browser zoom at 1280 and text-only zoom.

  • No horizontal overflow at any swept width.
  • Every task completable at 320 and at 1920.
  • Line length 45-80 characters for body text at every width.
  • Touch targets at least 44px where pointer: coarse.
  • Keyboard order matches visual order at each layout.

Output

## Responsive plan: <scope>
Breakpoints: sm 40rem, md 48rem, lg 64rem (existing: <...>, consolidated: <...>)
| Component | < sm | sm-md | md-lg | >= lg | Mechanism |
|---|---|---|---|---|---|
| Product card | stacked | stacked | media left | media left | container query 28rem |
Sweep result: <widths checked, issues found and fixed>

Related: phone-specific patterns (thumb reach, safe areas) in $mobile-ui-patterns; grid and container query internals in $modern-css-layout.

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Responsive Design"
  short_description: "Layouts that hold at every width, not three"
  default_prompt: "$responsive-design The site breaks between 800 and 1000 pixels wide, fix the layout"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem