---
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.
