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.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- responsive-design Installs to ~/.agents/skills/responsive-design/ for every project on this machine.
curl -fsSL codexskills.dev/cli.mjs -o codex-skills.mjsnode codex-skills.mjs install responsive-design The CLI also searches, updates and removes skills. Run it with no arguments to pick from a list. Needs Node 20.12+.
curl -fsSL codexskills.dev/install.sh \ | sh -s -- --project responsive-design Installs to .agents/skills/responsive-design/ in the current repository. Commit it and everyone who runs Codex there gets it.
curl -fsSLO codexskills.dev/downloads/responsive-design.zipunzip -o responsive-design.zip -d ~/.agents/skills/ The archive holds the skill folder with its generated agents/openai.yaml. Unzip into .agents/skills/ to scope it to a repo.
& ([scriptblock]::Create((irm codexskills.dev/install.ps1))) responsive-design PowerShell 5.1 or 7. Installs to %USERPROFILE%\.agents\skills\. Add -Project for the current repo.
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
- Phone-specific concerns like thumb reach, gestures and safe areas: use mobile-ui-patterns
- Serving different image sizes and formats per viewport: use responsive-images
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.
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-widthqueries 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-wrapandclamp()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:
| Token | Value | Typical change |
|---|---|---|
sm | 40rem (640px) | Two-up cards, inline form rows |
md | 48rem (768px) | Sidebar appears, tables leave card mode |
lg | 64rem (1024px) | Three columns, full navigation |
xl | 80rem (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
| Data | Small-screen treatment |
|---|---|
| Few columns, row = record | Stack to cards with data-label headers |
| Many numeric columns compared across rows | Horizontal scroll inside a focusable wrapper with sticky first column |
| Many columns, few needed on mobile | Priority 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); }
Navigation
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
100vwincludes the vertical scrollbar on desktop and causes horizontal scroll; use100%ordvw. Likewise preferdvh/svhtovhon mobile.- A single long word, URL or code block overflows narrow containers:
overflow-wrap: anywhereon user content,min-width: 0on grid and flex children. - Images without
max-width: 100%; height: autoand withoutwidth/heightattributes overflow and cause layout shift. Responsive image sources:$responsive-images. display: noneat a breakpoint still loads that content’s images and scripts; for heavy components, render conditionally or lazy load.- Ordering with
orderor 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.yaml
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.