CSS and Layout skill 1 of 3

Flexbox and Grid Layout SKILL.md: Overflow, Shrinking and 1fr

The Flexbox and Grid Layout skill makes Claude, Cursor or another AI agent find and fix CSS layouts that overflow, collapse or clip. A read-only checker flags bare 1fr tracks, wide auto-fit minimums and 100vw widths, then the agent measures overflow at four widths before and after and edits in small approved batches.

flexbox-grid-layout/SKILL.md, version 1.0.0, 3,285 words, plus scripts/layout_check.py.

An agent fixes broken Flexbox and Grid layouts in this order: run a read-only checker on the CSS, measure which elements stick out of the viewport at four widths, trace each one up to the flex or grid item that cannot shrink, apply a fixed fix from a table, then re-measure.

It works on plain CSS, SCSS output, CSS Modules and <style> blocks. Facts and sources sit in references/appendix.md, layout code in references/patterns.md.

When to use this skill, and when not to

Use it for horizontal scroll, columns that blow out, text that will not truncate, cards or sidebars that break on a phone, grid areas that do nothing, and choosing between flex and grid for a new layout.

RequestUse instead
Component width responding to its own containercontainer-queries.md
A rule that is overridden, !important chains, third-party CSScascade-layers.md
Fluid type, spacing scales, breakpoints for textOut of scope for this release
Colour, spacing taste, visual designOut of scope
A WCAG conformance statementA person with accessibility responsibility. The checker is not an audit

Guardrails

  1. Propose, then change. Report and plan first. Edit only after the user approves a batch, on a branch under version control. Never push, merge or deploy.
  2. Local pages only. Measure on a dev server or a local file. Do not load production pages signed in as a real user.
  3. No personal data in output. Layouts hold names, emails and prices. The measuring snippets in Templates print tag, class and pixel values only, never textContent, value or screenshots. Test with invented strings.
  4. Batches stay small. At most 5 rules or 30 declarations per batch (defaults), each shown as a diff.
  5. Nothing is invented. Thresholds are labelled defaults. Source facts carry a date. Version-dependent facts carry verify before relying on this.
  6. Not an accessibility audit. Passing the checks does not show WCAG conformance.
  7. Refuses to: add overflow-x: hidden to html or body as the fix, add !important, set fixed heights on text containers, move layout into JavaScript, or edit minified files.

Inputs the agent must have before starting

Ask for every missing item. Do not assume.

InputAsk exactly
Source CSS"Which source files (not minified) hold the layout, and which build step produces the served CSS?"
Symptom"What breaks, on which page or component, and at what viewport width?"
How to load the page"How do I open it locally, with fake data?"
Target browsers"Which browsers must work? Subgrid and dvh depend on it."
Design breakpoints"Which widths does the design define? Default 320, 375, 768, 1280."
Tests"Is there a visual regression or end-to-end suite I should run?"
Approval"May I edit on a branch in batches, showing each diff first?"

Raw SKILL.md file

.md

This is the exact file agents read, including the credit header and licence notice. Save it as flexbox-grid-layout/SKILL.md.

---
name: flexbox-grid-layout
description: "Audits and fixes CSS Flexbox and Grid layouts that overflow, collapse or clip. Runs a read-only checker for bare 1fr tracks, auto-fit minimums wider than a phone, wide fixed widths, 100vw, root overflow-x hidden, broken grid-template-areas and ellipsis text, then applies rules for flex or grid, min-width 0, wrapping and subgrid and measures overflow at 320, 375 and 768px. Use for horizontal scroll, text that will not truncate, cards or sidebars breaking on mobile. Do NOT use for container queries, cascade conflicts, fluid type or animation."
license: CC-BY-4.0
metadata:
  author: Afeez Adebayo
  author_url: https://afeezadebayo.com
  author_linkedin: https://www.linkedin.com/in/afeez-adebayo/
  author_x: https://x.com/za_icon
  source: https://afeezadebayo.com/skills-md/frontend-development/css-layout/flexbox-grid-layout/
  category: frontend-development
  subcategory: css-layout
  version: "1.0.0"
  created: "2026-10-25"
  updated: "2026-10-25"
---

# Flexbox and Grid Layout: Overflow, Shrinking and Track Sizing

An agent fixes broken Flexbox and Grid layouts in this order: run a read-only checker on the CSS, measure which elements stick out of the viewport at four widths, trace each one up to the flex or grid item that cannot shrink, apply a fixed fix from a table, then re-measure.

It works on plain CSS, SCSS output, CSS Modules and `<style>` blocks. Facts and sources sit in `references/appendix.md`, layout code in `references/patterns.md`.

## When to use this skill, and when not to

Use it for horizontal scroll, columns that blow out, text that will not truncate, cards or sidebars that break on a phone, grid areas that do nothing, and choosing between flex and grid for a new layout.

| Request | Use instead |
|---|---|
| Component width responding to its own container | `container-queries.md` |
| A rule that is overridden, `!important` chains, third-party CSS | `cascade-layers.md` |
| Fluid type, spacing scales, breakpoints for text | Out of scope for this release |
| Colour, spacing taste, visual design | Out of scope |
| A WCAG conformance statement | A person with accessibility responsibility. The checker is not an audit |

## Guardrails

1. **Propose, then change.** Report and plan first. Edit only after the user approves a batch, on a branch under version control. Never push, merge or deploy.
2. **Local pages only.** Measure on a dev server or a local file. Do not load production pages signed in as a real user.
3. **No personal data in output.** Layouts hold names, emails and prices. The measuring snippets in Templates print tag, class and pixel values only, never `textContent`, `value` or screenshots. Test with invented strings.
4. **Batches stay small.** At most 5 rules or 30 declarations per batch (defaults), each shown as a diff.
5. **Nothing is invented.** Thresholds are labelled defaults. Source facts carry a date. Version-dependent facts carry **verify before relying on this**.
6. **Not an accessibility audit.** Passing the checks does not show WCAG conformance.
7. **Refuses to:** add `overflow-x: hidden` to `html` or `body` as the fix, add `!important`, set fixed heights on text containers, move layout into JavaScript, or edit minified files.

## Inputs the agent must have before starting

Ask for every missing item. Do not assume.

| Input | Ask exactly |
|---|---|
| Source CSS | "Which source files (not minified) hold the layout, and which build step produces the served CSS?" |
| Symptom | "What breaks, on which page or component, and at what viewport width?" |
| How to load the page | "How do I open it locally, with fake data?" |
| Target browsers | "Which browsers must work? Subgrid and `dvh` depend on it." |
| Design breakpoints | "Which widths does the design define? Default 320, 375, 768, 1280." |
| Tests | "Is there a visual regression or end-to-end suite I should run?" |
| Approval | "May I edit on a branch in batches, showing each diff first?" |

## Workflow

### Step 0: Confirm scope

List the files. If the only CSS is minified, stop and ask for source: the checker's line numbers are all 1 on minified input. One page or component per run.

### Step 1: Run the checker

```
python3 scripts/layout_check.py src/styles/*.css pages/home.html | head -40
```

Read only its output. Do not read the script. On CSS under about 100 lines, read the file instead and skip to step 2. Exit code 1 means an error. Pass files in load order. HTML files are read for `<style>` blocks only, so pass linked `.css` files too. `--limit 288` changes the phone-width limit. Each code has one fix, in this table.

| Code | Level | Meaning | Fix |
|---|---|---|---|
| `fr-no-min` | warn | `1fr` is `minmax(auto, 1fr)`: the track grows to its content | `minmax(0, 1fr)`. Keep bare `fr` only when content-based growth is wanted and say so |
| `autofit-overflow` | warn | `auto-fit`/`auto-fill` minimum wider than 288px overflows a 320px viewport with 16px gutters | `minmax(min(100%, 320px), 1fr)` |
| `fixed-tracks` | warn | Fixed tracks total over 288px outside a min-width query | One column by default, add columns in a `min-width` query |
| `fixed-width` | warn | `width` or `min-width` over 320px | `max-width`, or move into a `min-width` query |
| `vw-width` | warn | `100vw` includes the scrollbar | `100%` or `inline-size: 100%` |
| `root-overflow-hidden` | warn | Overflow hidden on `html` or `body` hides the bug | Remove after step 3 finds the cause |
| `areas-ragged`, `areas-not-rect` | error | Rows with unequal cell counts, or a non-rectangular area, make the whole declaration invalid | Equal cells per row, each name one rectangle |
| `area-unknown` | warn | `grid-area` names no template area | Fix the name, or the template |
| `ellipsis-review` | info | Truncation needs `min-width: 0` on the flex or grid item | Step 5, row "text will not truncate" |
| `vh-height` | info | `100vh` on mobile | `min-height: 100vh; min-height: 100dvh;` (**verify before relying on this**) |
| `no-style-block` | info | An HTML file with no inline CSS | Pass the CSS files |

The checker reads static CSS. It cannot see content, computed layout or JavaScript, so step 2 is not optional.

### Step 2: Measure before

Run the overflow snippet (Templates) at 320, 375, 768 and 1280px, in a browser or a Playwright `page.evaluate`. It returns elements whose right edge passes the viewport. Record the list.

Never rely on `document.documentElement.scrollWidth` alone. With `overflow-x: hidden` on `html` or `body` it reports the viewport width while the content is wider. In the worked example it read 375 while the body was 1,480px wide.

### Step 3: Trace each offender to its cause

Run the ancestor snippet (Templates) on each offender. For every ancestor that is a flex or grid item it prints `min-width` and `overflow`.

| Finding | Cause |
|---|---|
| A flex or grid item with `min-width: auto` and `overflow: visible` above the offender | The item will not shrink below its content width |
| Nested flex containers, `min-width: 0` already on the innermost item | An outer item still has `auto`, which blocks the inner one |
| A `1fr` or `auto` track above the offender | The track grew to the content |
| `width` in px, `100vw`, or a `min-width` over the viewport | A fixed size |
| No ancestor matches | Not a layout problem. Check images without `max-width` and long unbroken strings |

### Step 4: Choose flex or grid for any new or rebuilt layout

| Situation | Use |
|---|---|
| Items in one row or column, sized by their content, wrapping optional | Flex |
| Items that must line up in rows and columns at once | Grid |
| Page shell, cards in a responsive grid, form label and field pairs | Grid |
| Nav bar, toolbar, button group, media object | Flex |
| Card rows where inner parts (title, text, button) must align across cards | Grid with `subgrid` rows, fallback to ordinary grid |
| Unknown number of items of unknown size, centring one item | Flex, or `place-items: center` on grid |

Use `gap`, not margins between items. If you are nesting more than two levels of flex to align things in two directions, switch that region to grid.

### Step 5: Apply the fix for each cause

| Symptom | Fix | Trade-off |
|---|---|---|
| Column pushed wide by a long line, table or image | `grid-template-columns: minmax(0, 1fr) 300px`, or `min-width: 0` on the item in that column | `minmax(0, 1fr)` removes the track's ability to grow to content, so wide content overflows its own box |
| `pre` or table still overflows | `overflow-x: auto` on the `pre`, or on a wrapper around the table | The element scrolls on its own |
| Text will not truncate | `white-space: nowrap; overflow: hidden; text-overflow: ellipsis` on the text element, and `min-width: 0` on the flex or grid item that contains it. Text directly in the item needs no `min-width` | None |
| Nested flex still overflows | `min-width: 0` on every flex item in the chain, outermost first | None |
| Item will not shrink and clipping is acceptable | `overflow: hidden` on the item. Its automatic minimum becomes 0 | Clips shadows, tooltips and focus rings that extend outside it |
| `auto-fit` grid overflows on a phone | `minmax(min(100%, 320px), 1fr)` | None |
| `auto-fit` or `auto-fill` | `auto-fit` collapses empty tracks so items stretch. `auto-fill` keeps empty tracks, so items keep a fixed size | Pick one per layout and say which |
| Fixed width on a container | `max-width: 480px; width: 100%` | None |
| Wide columns by default | Single column first, then `@media (min-width: 48em)` adds the second | Mobile-first. 48em is a default |
| Full-width hero `100vw` | `100%` | None |
| Cards with unaligned inner parts | `display: grid; grid-template-rows: subgrid; grid-row: span 3;` inside a card grid | Subgrid is Baseline 2023 (**verify before relying on this**). Without it the layout works but inner rows do not align |
| Template areas ignored | Equal cell count per row, `.` for empty cells, each name one rectangle | None |

Do not fix an overflow by hiding it. Do not add a breakpoint to patch one width.

### Step 6: Apply in batches

Group by cause, at most 5 rules per batch, diff first, approval, then edit in place. Do not rewrite whole files or echo unchanged code.

### Step 7: Verify

1. Run the checker again. Errors must be 0. Each remaining warning is fixed or listed with a reason.
2. Run the overflow snippet at 320, 375, 768 and 1280. It must return an empty list at each.
3. Put a 200-character unbroken string and the longest real title into the offending component. It must not widen the page.
4. Zoom to 200% at 1280px, which acts as a 640px viewport. Nothing may need two-way scrolling except data tables and code blocks.
5. Run the existing test suite if there is one.
6. List what you could not test: real mobile browsers (for `dvh` and scrollbar width), engines other than the one you used.

### Step 8: Report

Use the report template. Keep it to a short list of file, line, issue and fix.

## Worked example

An invented docs page: a `1fr 300px` layout with a long `pre`, a hero at `width: 100vw`, an `auto-fit` card grid with `minmax(320px, 1fr)`, a card title with ellipsis inside a flex row, a ragged `grid-template-areas`, and `overflow-x: hidden` on `html, body`.

Step 1, `python3 scripts/layout_check.py page.css`:

```
page.css:17  error  areas-ragged  .page: grid-template-areas rows have [1, 2] cells; the whole declaration is invalid and ignored
page.css:10  warn  autofit-overflow  .cards: track minimum 320px (320px) exceeds 288px; ...
page.css:5  warn  fixed-tracks  .layout: fixed tracks total 300px outside a min-width query; ...
page.css:24  warn  fixed-width  .pricing: min-width: 480px exceeds a 320px viewport; ...
page.css:5  warn  fr-no-min  .layout: bare fr track in `1fr 300px` grows with content; ...
page.css:3  warn  vw-width  .hero: width: 100vw includes the scrollbar; ...
page.css:1  warn  root-overflow-hidden  html, body: overflow hidden on the root hides overflow ...
errors 1, warnings 6, info 2
```

Step 2 at 375px: `document.documentElement.scrollWidth` is 375. The overflow snippet lists `main` and `pre` ending at 1,156px and `aside` ending at 1,480px. Step 3 shows the `1fr` track as the cause: the `pre` line sets the track's minimum.

Step 5 fixes, in two batches (five rules, then four): `minmax(0, 1fr)` with the 300px track moved into `@media (min-width: 48em)`, `overflow-x: auto` on `pre`, `minmax(min(100%, 320px), 1fr)` on the card grid, `inline-size: 100%` on the hero, and `min-width: 0` on the title; then equal-cell template areas, the matching `grid-area` name, `max-width` on the pricing block and the root `overflow-x: hidden` removed.

Step 7: checker `errors 0, warnings 0, info 1`. The overflow snippet returns `[]` at 320, 375 and 768px. Measured in Chromium 153 on 25 October 2026. The checker's `ellipsis-review` stays as info because the title is the flex item itself and carries `min-width: 0`.

## Templates

### Overflow snippet (step 2)

```js
(() => { const vw = document.documentElement.clientWidth, out = [];
  for (const e of document.querySelectorAll('body *')) {
    const r = e.getBoundingClientRect();
    if (r.right > vw + 0.5) out.push(e.tagName.toLowerCase() + (e.className && typeof e.className === 'string' ? '.' + e.className.split(' ')[0] : '') + ':' + Math.round(r.right));
  }
  return { viewport: vw, offenders: out.slice(0, 10), more: Math.max(0, out.length - 10) }; })()
```

### Ancestor snippet (step 3)

Replace `SELECTOR` with one offender.

```js
(() => { let e = document.querySelector('SELECTOR'), rows = [];
  while (e && e !== document.body) {
    const s = getComputedStyle(e), p = e.parentElement ? getComputedStyle(e.parentElement) : {};
    const item = /flex|grid/.test(p.display || '');
    rows.push([e.tagName.toLowerCase() + '.' + String(e.className).split(' ')[0], 'item=' + item, 'display=' + s.display, 'min-width=' + s.minWidth, 'overflow-x=' + s.overflowX, 'w=' + Math.round(e.getBoundingClientRect().width)].join(' '));
    e = e.parentElement;
  } return rows; })()
```

An ancestor with `item=true`, `min-width=auto` and `overflow-x=visible` is a candidate for `min-width: 0`.

### Report

```
Layout report: <page or component>, <date>
Checker before: errors N, warnings N. After: errors N, warnings N.
Overflow before (px right edge, at 375): <selector:px, ...>. After: [] at 320, 375, 768, 1280.
Changes: <file:line  issue  fix>   (one line each)
Left as is: <warning  reason>
Not tested: <items>
```

### Starting prompt

```
Use the flexbox-grid-layout skill on <page>. Source CSS: <paths>. Symptom: <what breaks at what width>.
Load the page from <local URL> with fake data. Target browsers: <list>. Edit on a branch in batches of at most 5 rules and show each diff first.
```

## Failure modes and anti-patterns

| Mistake | How to spot it | Do instead |
|---|---|---|
| Hiding the overflow with `overflow-x: hidden` | `scrollWidth` equals the viewport but the snippet lists offenders. Content is clipped, not fixed | Step 3, then remove the root rule |
| Fixing only the innermost element in nested flex | `min-width: 0` is present and the page still overflows | `min-width: 0` on every item in the chain (step 5) |
| Treating `1fr` as an equal share | Columns differ in width when their content differs | `minmax(0, 1fr)`, or `repeat(3, minmax(0, 1fr))` |
| Testing at desktop width or in one engine | Passes at 1280px, fails on a phone. Firefox and Edge have differed from Chrome on `white-space: nowrap` in flex items (DEV Community, 2020) | Four widths, and a second engine when installed |
| Patching with breakpoints | A `max-width` media query overrides a fixed desktop width | Mobile-first base, wide layout in `min-width` queries |

## Quality bar

Run every item before handing over.

1. Checker errors are 0 and each warning is fixed or justified in the report.
2. The overflow snippet returns an empty list at 320, 375, 768 and 1280px.
3. No `overflow-x: hidden` was added to `html` or `body`, and none was left in place without a stated reason.
4. No fixed `width` or `min-width` over 320px remains outside a `min-width` query.
5. Every changed line appears in the report with file, line, issue and fix.
6. The diff touches only flagged rules and has no whole-file rewrites.
7. The report lists what was not tested.
8. No page text, form values or screenshots appear in the output.

## Cost

Figures are estimates from this skill's own count (words × 1.35 for prose, characters ÷ 3.5 for code and tables), not from a model tokeniser. Rival figures are estimates from the excerpts I read.

| Item | Tokens | Status | Read condition |
|---|---|---|---|
| A. Description (always loaded) | 116 | Estimate | Every session with the skill installed |
| B. `SKILL.md` body | 4,811 | Estimate | When the skill fires |
| C. `references/appendix.md` | 904 | Estimate | Only to check a claim or a measurement |
| C. `references/patterns.md` | 522 | Estimate | Only when writing or rebuilding a layout |
| Script output: `layout_check.py` (worked example) plus measuring snippets | 606 | Estimate | Every run. Checker output is capped with `head -40`, about 1,424 tokens |
| D. Typical run (A + B + script and snippet output) | 5,533 | Estimate | Common path: fix flagged lines, no references |
| D. Worst case (A + B + both references + 40 lines of output) | 8,277 | Estimate | Rebuilding a layout, many findings |
| E. Cheaper path | 5,345 | Estimate | Run the checker, fix only flagged lines, measure at 375px only, skip the references |

Rival sizes, estimated from the excerpts I read (SKILL.md only, files they link were not sized): pluginagentmarketplace css-flexbox-grid about 700 words, roughly 950 tokens, with five other files listed; onewave-ai responsive-layout-builder about 800 words, roughly 1,080 tokens; wshobson responsive-design about 250 to 300 words, roughly 340 to 405 tokens, plus `references/details.md`. This skill costs more to load than all three. What the checker saves is the agent reading and reasoning over every rule in a large stylesheet. Measured on a real 135,539-character minified stylesheet (mkdocs readthedocs `theme.css`), the checker printed 255 characters, about 73 tokens, against about 38,700 tokens to read the file. On the 21-line worked example its output (about 360 tokens) is larger than the file (about 170 tokens), so on a stylesheet under about 100 lines read the file instead and use the snippets in step 2.

## Handoffs

`container-queries.md` covers components that respond to their container. `cascade-layers.md` covers rules that lose to other rules. `responsive-images.md` covers images in grids. `dialog-and-popover.md` covers overlays.

## Appendix

Tool facts and sources are in `references/appendix.md`. Layout code is in `references/patterns.md`.

## Sources

Last verified 25 October 2026 for every source, except where a date says otherwise.

- Anthropic, Skill authoring best practices: https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices
- Anthropic, Agent Skills overview: https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview
- CSS-Tricks, Preventing a Grid Blowout (1 October 2018): https://css-tricks.com/?p=276814
- CSS-Tricks, truncating text in a flex child (modified 8 February 2017): https://css-tricks.com/?p=241496
- DEV Community, Flexbox Gotchas Reloaded (edited 28 June 2022): https://dev.to/hbarcelos/flexbox-gotchas-reloaded-2i39
- web.dev, Baseline 2023 (updated 12 December 2023): https://web.dev/blog/baseline2023
- mustafa.net, Why your CSS grid breaks on mobile (31 July 2026): https://mustafa.net/2026/07/31/why-your-css-grid-breaks-on-mobile-and-the-one-line-fix/
- pluginagentmarketplace, css-flexbox-grid (via playbooks.com). Rival implementation: https://playbooks.com/skills/pluginagentmarketplace/custom-plugin-css/css-flexbox-grid
- onewave-ai, responsive-layout-builder (via skillselion.com). Rival implementation: https://skillselion.com/skills/onewave-ai/claude-skills/responsive-layout-builder
- wshobson, responsive-design (via smithery.ai). Rival implementation: https://smithery.ai/skills/wshobson/responsive-design

---
Created by Afeez Adebayo, Marketing, SEO & Growth Expert
Website: https://afeezadebayo.com
LinkedIn: https://www.linkedin.com/in/afeez-adebayo/
X: https://x.com/za_icon
Source: https://afeezadebayo.com/skills-md/frontend-development/css-layout/flexbox-grid-layout/

Licence: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/). You may copy, share and adapt this skill, including for commercial use, as long as you credit Afeez Adebayo and link to the source URL above. Keep this notice in any copy or adapted version.

Workflow

Step 0: Confirm scope

List the files. If the only CSS is minified, stop and ask for source: the checker's line numbers are all 1 on minified input. One page or component per run.

Step 1: Run the checker

python3 scripts/layout_check.py src/styles/*.css pages/home.html | head -40

Read only its output. Do not read the script. On CSS under about 100 lines, read the file instead and skip to step 2. Exit code 1 means an error. Pass files in load order. HTML files are read for <style> blocks only, so pass linked .css files too. --limit 288 changes the phone-width limit. Each code has one fix, in this table.

CodeLevelMeaningFix
fr-no-minwarn1fr is minmax(auto, 1fr): the track grows to its contentminmax(0, 1fr). Keep bare fr only when content-based growth is wanted and say so
autofit-overflowwarnauto-fit/auto-fill minimum wider than 288px overflows a 320px viewport with 16px guttersminmax(min(100%, 320px), 1fr)
fixed-trackswarnFixed tracks total over 288px outside a min-width queryOne column by default, add columns in a min-width query
fixed-widthwarnwidth or min-width over 320pxmax-width, or move into a min-width query
vw-widthwarn100vw includes the scrollbar100% or inline-size: 100%
root-overflow-hiddenwarnOverflow hidden on html or body hides the bugRemove after step 3 finds the cause
areas-ragged, areas-not-recterrorRows with unequal cell counts, or a non-rectangular area, make the whole declaration invalidEqual cells per row, each name one rectangle
area-unknownwarngrid-area names no template areaFix the name, or the template
ellipsis-reviewinfoTruncation needs min-width: 0 on the flex or grid itemStep 5, row "text will not truncate"
vh-heightinfo100vh on mobilemin-height: 100vh; min-height: 100dvh; (verify before relying on this)
no-style-blockinfoAn HTML file with no inline CSSPass the CSS files

The checker reads static CSS. It cannot see content, computed layout or JavaScript, so step 2 is not optional.

Step 2: Measure before

Run the overflow snippet (Templates) at 320, 375, 768 and 1280px, in a browser or a Playwright page.evaluate. It returns elements whose right edge passes the viewport. Record the list.

Never rely on document.documentElement.scrollWidth alone. With overflow-x: hidden on html or body it reports the viewport width while the content is wider. In the worked example it read 375 while the body was 1,480px wide.

Step 3: Trace each offender to its cause

Run the ancestor snippet (Templates) on each offender. For every ancestor that is a flex or grid item it prints min-width and overflow.

FindingCause
A flex or grid item with min-width: auto and overflow: visible above the offenderThe item will not shrink below its content width
Nested flex containers, min-width: 0 already on the innermost itemAn outer item still has auto, which blocks the inner one
A 1fr or auto track above the offenderThe track grew to the content
width in px, 100vw, or a min-width over the viewportA fixed size
No ancestor matchesNot a layout problem. Check images without max-width and long unbroken strings

Step 4: Choose flex or grid for any new or rebuilt layout

SituationUse
Items in one row or column, sized by their content, wrapping optionalFlex
Items that must line up in rows and columns at onceGrid
Page shell, cards in a responsive grid, form label and field pairsGrid
Nav bar, toolbar, button group, media objectFlex
Card rows where inner parts (title, text, button) must align across cardsGrid with subgrid rows, fallback to ordinary grid
Unknown number of items of unknown size, centring one itemFlex, or place-items: center on grid

Use gap, not margins between items. If you are nesting more than two levels of flex to align things in two directions, switch that region to grid.

Step 5: Apply the fix for each cause

SymptomFixTrade-off
Column pushed wide by a long line, table or imagegrid-template-columns: minmax(0, 1fr) 300px, or min-width: 0 on the item in that columnminmax(0, 1fr) removes the track's ability to grow to content, so wide content overflows its own box
pre or table still overflowsoverflow-x: auto on the pre, or on a wrapper around the tableThe element scrolls on its own
Text will not truncatewhite-space: nowrap; overflow: hidden; text-overflow: ellipsis on the text element, and min-width: 0 on the flex or grid item that contains it. Text directly in the item needs no min-widthNone
Nested flex still overflowsmin-width: 0 on every flex item in the chain, outermost firstNone
Item will not shrink and clipping is acceptableoverflow: hidden on the item. Its automatic minimum becomes 0Clips shadows, tooltips and focus rings that extend outside it
auto-fit grid overflows on a phoneminmax(min(100%, 320px), 1fr)None
auto-fit or auto-fillauto-fit collapses empty tracks so items stretch. auto-fill keeps empty tracks, so items keep a fixed sizePick one per layout and say which
Fixed width on a containermax-width: 480px; width: 100%None
Wide columns by defaultSingle column first, then @media (min-width: 48em) adds the secondMobile-first. 48em is a default
Full-width hero 100vw100%None
Cards with unaligned inner partsdisplay: grid; grid-template-rows: subgrid; grid-row: span 3; inside a card gridSubgrid is Baseline 2023 (verify before relying on this). Without it the layout works but inner rows do not align
Template areas ignoredEqual cell count per row, . for empty cells, each name one rectangleNone

Do not fix an overflow by hiding it. Do not add a breakpoint to patch one width.

Step 6: Apply in batches

Group by cause, at most 5 rules per batch, diff first, approval, then edit in place. Do not rewrite whole files or echo unchanged code.

Step 7: Verify

  1. Run the checker again. Errors must be 0. Each remaining warning is fixed or listed with a reason.
  2. Run the overflow snippet at 320, 375, 768 and 1280. It must return an empty list at each.
  3. Put a 200-character unbroken string and the longest real title into the offending component. It must not widen the page.
  4. Zoom to 200% at 1280px, which acts as a 640px viewport. Nothing may need two-way scrolling except data tables and code blocks.
  5. Run the existing test suite if there is one.
  6. List what you could not test: real mobile browsers (for dvh and scrollbar width), engines other than the one you used.

Step 8: Report

Use the report template. Keep it to a short list of file, line, issue and fix.

Worked example

An invented docs page: a 1fr 300px layout with a long pre, a hero at width: 100vw, an auto-fit card grid with minmax(320px, 1fr), a card title with ellipsis inside a flex row, a ragged grid-template-areas, and overflow-x: hidden on html, body.

Step 1, python3 scripts/layout_check.py page.css:

page.css:17  error  areas-ragged  .page: grid-template-areas rows have [1, 2] cells; the whole declaration is invalid and ignored
page.css:10  warn  autofit-overflow  .cards: track minimum 320px (320px) exceeds 288px; ...
page.css:5  warn  fixed-tracks  .layout: fixed tracks total 300px outside a min-width query; ...
page.css:24  warn  fixed-width  .pricing: min-width: 480px exceeds a 320px viewport; ...
page.css:5  warn  fr-no-min  .layout: bare fr track in `1fr 300px` grows with content; ...
page.css:3  warn  vw-width  .hero: width: 100vw includes the scrollbar; ...
page.css:1  warn  root-overflow-hidden  html, body: overflow hidden on the root hides overflow ...
errors 1, warnings 6, info 2

Step 2 at 375px: document.documentElement.scrollWidth is 375. The overflow snippet lists main and pre ending at 1,156px and aside ending at 1,480px. Step 3 shows the 1fr track as the cause: the pre line sets the track's minimum.

Step 5 fixes, in two batches (five rules, then four): minmax(0, 1fr) with the 300px track moved into @media (min-width: 48em), overflow-x: auto on pre, minmax(min(100%, 320px), 1fr) on the card grid, inline-size: 100% on the hero, and min-width: 0 on the title; then equal-cell template areas, the matching grid-area name, max-width on the pricing block and the root overflow-x: hidden removed.

Step 7: checker errors 0, warnings 0, info 1. The overflow snippet returns [] at 320, 375 and 768px. Measured in Chromium 153 on 25 October 2026. The checker's ellipsis-review stays as info because the title is the flex item itself and carries min-width: 0.

Templates

Overflow snippet (step 2)

(() => { const vw = document.documentElement.clientWidth, out = [];
  for (const e of document.querySelectorAll('body *')) {
    const r = e.getBoundingClientRect();
    if (r.right > vw + 0.5) out.push(e.tagName.toLowerCase() + (e.className && typeof e.className === 'string' ? '.' + e.className.split(' ')[0] : '') + ':' + Math.round(r.right));
  }
  return { viewport: vw, offenders: out.slice(0, 10), more: Math.max(0, out.length - 10) }; })()

Ancestor snippet (step 3)

Replace SELECTOR with one offender.

(() => { let e = document.querySelector('SELECTOR'), rows = [];
  while (e && e !== document.body) {
    const s = getComputedStyle(e), p = e.parentElement ? getComputedStyle(e.parentElement) : {};
    const item = /flex|grid/.test(p.display || '');
    rows.push([e.tagName.toLowerCase() + '.' + String(e.className).split(' ')[0], 'item=' + item, 'display=' + s.display, 'min-width=' + s.minWidth, 'overflow-x=' + s.overflowX, 'w=' + Math.round(e.getBoundingClientRect().width)].join(' '));
    e = e.parentElement;
  } return rows; })()

An ancestor with item=true, min-width=auto and overflow-x=visible is a candidate for min-width: 0.

Report

Layout report: <page or component>, <date>
Checker before: errors N, warnings N. After: errors N, warnings N.
Overflow before (px right edge, at 375): <selector:px, ...>. After: [] at 320, 375, 768, 1280.
Changes: <file:line  issue  fix>   (one line each)
Left as is: <warning  reason>
Not tested: <items>

Starting prompt

Use the flexbox-grid-layout skill on <page>. Source CSS: <paths>. Symptom: <what breaks at what width>.
Load the page from <local URL> with fake data. Target browsers: <list>. Edit on a branch in batches of at most 5 rules and show each diff first.

Failure modes and anti-patterns

MistakeHow to spot itDo instead
Hiding the overflow with overflow-x: hiddenscrollWidth equals the viewport but the snippet lists offenders. Content is clipped, not fixedStep 3, then remove the root rule
Fixing only the innermost element in nested flexmin-width: 0 is present and the page still overflowsmin-width: 0 on every item in the chain (step 5)
Treating 1fr as an equal shareColumns differ in width when their content differsminmax(0, 1fr), or repeat(3, minmax(0, 1fr))
Testing at desktop width or in one enginePasses at 1280px, fails on a phone. Firefox and Edge have differed from Chrome on white-space: nowrap in flex items (DEV Community, 2020)Four widths, and a second engine when installed
Patching with breakpointsA max-width media query overrides a fixed desktop widthMobile-first base, wide layout in min-width queries

Quality bar

Run every item before handing over.

  1. Checker errors are 0 and each warning is fixed or justified in the report.
  2. The overflow snippet returns an empty list at 320, 375, 768 and 1280px.
  3. No overflow-x: hidden was added to html or body, and none was left in place without a stated reason.
  4. No fixed width or min-width over 320px remains outside a min-width query.
  5. Every changed line appears in the report with file, line, issue and fix.
  6. The diff touches only flagged rules and has no whole-file rewrites.
  7. The report lists what was not tested.
  8. No page text, form values or screenshots appear in the output.

Cost

Figures are estimates from this skill's own count (words × 1.35 for prose, characters ÷ 3.5 for code and tables), not from a model tokeniser. Rival figures are estimates from the excerpts I read.

ItemTokensStatusRead condition
A. Description (always loaded)116EstimateEvery session with the skill installed
B. SKILL.md body4,811EstimateWhen the skill fires
C. references/appendix.md904EstimateOnly to check a claim or a measurement
C. references/patterns.md522EstimateOnly when writing or rebuilding a layout
Script output: layout_check.py (worked example) plus measuring snippets606EstimateEvery run. Checker output is capped with head -40, about 1,424 tokens
D. Typical run (A + B + script and snippet output)5,533EstimateCommon path: fix flagged lines, no references
D. Worst case (A + B + both references + 40 lines of output)8,277EstimateRebuilding a layout, many findings
E. Cheaper path5,345EstimateRun the checker, fix only flagged lines, measure at 375px only, skip the references

Rival sizes, estimated from the excerpts I read (SKILL.md only, files they link were not sized): pluginagentmarketplace css-flexbox-grid about 700 words, roughly 950 tokens, with five other files listed; onewave-ai responsive-layout-builder about 800 words, roughly 1,080 tokens; wshobson responsive-design about 250 to 300 words, roughly 340 to 405 tokens, plus references/details.md. This skill costs more to load than all three. What the checker saves is the agent reading and reasoning over every rule in a large stylesheet. Measured on a real 135,539-character minified stylesheet (mkdocs readthedocs theme.css), the checker printed 255 characters, about 73 tokens, against about 38,700 tokens to read the file. On the 21-line worked example its output (about 360 tokens) is larger than the file (about 170 tokens), so on a stylesheet under about 100 lines read the file instead and use the snippets in step 2.

Handoffs

container-queries.md covers components that respond to their container. cascade-layers.md covers rules that lose to other rules. responsive-images.md covers images in grids. dialog-and-popover.md covers overlays.

Appendix

Tool facts and sources are in references/appendix.md. Layout code is in references/patterns.md.

Sources

Last verified 25 October 2026 for every source, except where a date says otherwise.

What this skill does

Layouts fail at widths nobody tested. A 1fr column grows to fit a long line of code, a flex item will not shrink below its text, or a hero set to 100vw adds a sideways scroll bar once a vertical one appears. The usual patch is overflow-x: hidden on the body, which hides the damage. In this skill’s worked example the page reported a scroll width of 375px while its content was 1,480px wide.

The skill runs a read-only Python checker that reports bare fr tracks, auto-fit minimums wider than a phone, fixed widths, 100vw, root overflow-x: hidden, broken grid-template-areas and ellipsis text that needs min-width: 0. A short snippet then measures which elements pass the viewport at 320, 375, 768 and 1280px, and a second snippet traces each one to the flex or grid item that cannot shrink. Fixes come from a table with the trade-off beside each one, and edits go in batches of at most 5 rules, each needing your yes.

I read three published skills on the same ground before writing this one. One has a decision matrix and cheatsheets but no checker and no coverage of min-width: 0. One has copy-ready layouts and no overflow handling. One is short and lists common issues by name, without causes or fixes. I did not find a checker script in any of them.

Who it is for

Use it if you build or review page shells, card grids, sidebars, toolbars and truncating rows and want an agent to fix overflow without hiding it. It suits frontend developers, theme builders and anyone checking CSS that an AI tool wrote. It reads CSS and <style> blocks, so it works with any framework that outputs CSS.

It is the wrong skill for components that should respond to their own container (use Container Queries), for rules that lose to other rules (use Cascade Layers), for fluid type, animation and visual design, and for a WCAG conformance statement.

What is inside

The file is 3,285 words (version 1.0.0) with one script and two reference files. It holds:

  • Seven guardrails, including local pages only, no page text or screenshots in the output and no overflow-x: hidden as a fix.
  • Seven inputs the agent must have first, with the exact question for each.
  • A workflow of steps 0 to 8 with a table that gives one fix per checker code, a cause table, a flex-or-grid table and a symptom, fix and trade-off table.
  • One standard-library script, scripts/layout_check.py, with 12 problem codes. It read a 135 KB minified stylesheet in about 0.2 seconds.
  • A worked example with real checker output (1 error and 6 warnings before, 0 and 0 after), measured in Chromium 153.
  • Two measuring snippets, a report template and a starting prompt, five failure modes and an eight-item quality bar.
  • Two reference files: layout patterns, and an appendix with sources and 11 browser measurements.

The token costs below are estimates from the skill’s own count: words times 1.35 for prose and characters divided by 3.5 for code and tables. They are not from a model tokeniser.

ItemTokensStatus
Description (always loaded)116Estimate
SKILL.md body (when the skill fires)4,811Estimate
references/patterns.md, read only when writing or rebuilding a layout522Estimate
references/appendix.md, read only to check a claim904Estimate
Typical run (description, body, checker and snippet output)5,533Estimate
Cheaper path (checker, fix flagged lines, one width, no references)5,345Estimate
Worst case (both references, 40 lines of checker output)8,277Estimate

This skill costs more to load than the three rivals I read, which are roughly 340 to 1,080 tokens for SKILL.md alone. The checker saves the agent from reading a large stylesheet: on a 135,539-character minified file it printed about 73 tokens against about 38,700 tokens to read the file. On a stylesheet under about 100 lines the output is larger than the file, and the skill says to read the file instead.

How to install and use it in Claude, Cursor and other agents

Claude. Keep the folder as flexbox-grid-layout/ with SKILL.md, scripts/ and references/ inside, and zip it. In Claude, open Customize, then Skills, then Upload a skill. In Claude Code, put the folder in ~/.claude/skills/ or .claude/skills/ in a project.

Cursor and other agents. Put the folder where your tool reads skills, or paste the body into its rules and keep the script beside your code. Then send the starting prompt from the Templates section.

Before you install. Read the script first. It reads files and writes nothing. The skill tells the agent to measure only local pages with invented data and never to print page text. Install skills only from sources you trust.

A worked example

An invented docs page has a 1fr 300px layout with a long pre, a hero at 100vw, an auto-fit card grid with a 320px minimum, a card title with ellipsis in a flex row, a ragged grid-template-areas and overflow-x: hidden on the root. The checker reports 1 error and 6 warnings.

At 375px the document reports a scroll width of 375px, but the overflow snippet finds the aside ending at 1,480px. The ancestor snippet points at the 1fr track. The agent applies two batches: minmax(0, 1fr) with the sidebar column moved into a min-width query, overflow-x: auto on the pre, a min() in the card minimum, 100% for the hero, min-width: 0 on the title, then equal-cell template areas and the root rule removed. The checker then reports 0 errors and 0 warnings, and the snippet returns an empty list at 320, 375 and 768px.

Common mistakes

The skill is built around five ways this goes wrong:

  • Hiding the overflow with overflow-x: hidden. The page looks fixed and the content is clipped. The skill measures element edges, not document scroll width.
  • Fixing only the innermost flex item. An outer item with min-width: auto still blocks it. The skill sets min-width: 0 on every item in the chain.
  • Treating 1fr as an equal share. Columns differ when their content differs. minmax(0, 1fr) fixes it.
  • Testing at desktop width or in one engine. The skill measures four widths and asks for a second engine where one is installed.
  • Patching with breakpoints. A max-width query that overrides a fixed width hides the cause. The skill moves to a mobile-first base.

Container Queries covers components that respond to their own container and Cascade Layers covers rules that lose to other rules. Responsive Images covers images inside grids. Browse the CSS and Layout set, the full Frontend Development category or the Skills-md library.

Frequently asked questions

A track written 1fr is really minmax(auto, 1fr), so its minimum is the width of its content, and a long line of code or a wide table stretches the column. Write minmax(0, 1fr) or put min-width: 0 on the item in that column, as Chris Coyier showed in 2018. The checker flags bare fr tracks as fr-no-min.

Put white-space: nowrap, overflow: hidden and text-overflow: ellipsis on the text element, and min-width: 0 on the flex item that contains it. Text sitting directly in the flex item needs no min-width. If the row sits inside another flex item, give that item min-width: 0 too. The step 3 snippet shows which ancestor to change.

Flex items default to min-width: auto, so they stop shrinking at their content width. In nested flex layouts an outer item with auto blocks inner items even when they have min-width: 0. Set it on every item in the chain, outermost first. Measured in Chromium 153, setting it only on the innermost item left a 1,600px text box in a 320px viewport.

Use flex for one row or column of items sized by their content, such as nav bars, toolbars and button groups. Use grid when items must line up in rows and columns, as in page shells and card grids. If you nest more than two levels of flex to align things in two directions, switch that region to grid. Step 4 of the skill has the full table.

100vw includes the width of a vertical scrollbar, so a full-width element is wider than the space left for the page. In Chromium 153 with classic scrollbars, an 800px viewport gave a client width of 785px and a scroll width of 800px. Use width: 100% instead. Overlay scrollbars on phones and Macs hide the problem, so test with classic scrollbars.

No. It clips the overflow and removes the scroll bar, so the page looks fixed while content is cut off. In the skill’s worked example the document scroll width read 375px while the content was 1,480px wide. Find the widest element, fix its track or min-width and remove the rule. The checker flags it as root-overflow-hidden.

The description is about 116 tokens and loads in every session. The SKILL.md body is about 4,800 tokens when the skill fires. A typical run is about 5,500 tokens with checker output, the cheapest path is about 5,300 and the worst case is about 8,300. All figures are estimates, not from a model tokeniser.

Changelog

  • 1.0.0, 25 October 2026: first release.

Use, adapt and share this skill under CC BY 4.0: credit Afeez Adebayo and link to this page.