ScreenshotNeo

BlogGuides

CSS Flexbox: A Practical Guide

Learn how Flexbox axes, sizing, wrapping, and alignment work, then build and debug practical layouts with runnable examples.

By the ScreenshotNeo team4 October 20269 min read

CSS Flexbox arranges items along one axis at a time. Set display: flex on a parent to create a flex container; its in-flow children become flex items. The flex-direction property sets the main axis, and the cross axis runs perpendicular to it. Use Flexbox for relationships in one direction, such as a navigation bar, toolbar, or row of cards. Use CSS Grid when you need to control rows and columns together.

This guide builds a responsive card row and a compact toolbar, explains sizing and alignment, and shows how to diagnose common layout surprises. It assumes basic HTML and CSS.

1. The Flexbox mental model

Think of the container as laying its items out along a main axis. The cross axis is perpendicular. The default flex-direction is row, so the main axis follows the inline direction (left to right in a typical left-to-right page) and the cross axis follows the block direction. With column, those roles switch. Axis-relative language stays useful when direction or writing mode changes.

.toolbar {
  display: flex;
  flex-direction: row;
}

.stack {
  display: flex;
  flex-direction: column;
}

The element with display: flex is the flex container; its in-flow children are flex items. A flex item can itself be another flex container, so layouts can be composed from nested one-dimensional groups.

Property Axis or behavior Typical use
flex-direction Sets main axis row, row-reverse, column, column-reverse
justify-content Distributes items along the main axis Space a toolbar or center a short row
align-items Aligns items along the cross axis Vertically center controls in a row
align-self Overrides cross-axis alignment for one item Align one card differently
flex-wrap Controls whether items stay on one line Let cards move to additional lines

2. Build a responsive card group

Start with a small, runnable HTML file. Save it as flexbox.html and open it in a browser. Resize the viewport to observe wrapping.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Flexbox cards</title>
  <style>
    * { box-sizing: border-box; }
    body { margin: 0; padding: 2rem; font: 1rem/1.5 system-ui, sans-serif; color: #172033; }
    .cards {
      display: flex;
      flex-flow: row wrap;
      gap: 1rem;
      align-items: stretch;
    }
    .card {
      flex: 1 1 14rem;
      min-width: 0;
      padding: 1.25rem;
      border: 1px solid #cbd5e1;
      border-radius: .75rem;
      background: #f8fafc;
    }
    .card h2 { margin: 0 0 .5rem; font-size: 1.15rem; }
    .card p { margin: 0; }
  </style>
</head>
<body>
  <main class="cards">
    <article class="card"><h2>Plan</h2><p>Choose a sensible starting point.</p></article>
    <article class="card"><h2>Build</h2><p>Arrange content around its relationships.</p></article>
    <article class="card"><h2>Review</h2><p>Resize and inspect the result.</p></article>
  </main>
</body>
</html>

flex-flow is shorthand for flex-direction and flex-wrap. Here it means items flow in a row and wrap onto additional flex lines when they no longer fit. gap adds consistent space between items without adding margins to the outer edges. Each line is laid out independently along the main axis; wrapping does not make Flexbox a two-dimensional grid.

Make a toolbar

For a row with a title at the start and actions at the end, let the title consume available positive space:

.toolbar {
  display: flex;
  align-items: center;
  gap: .75rem;
}
.toolbar__title { margin-right: auto; }
.toolbar__actions { display: flex; gap: .5rem; }

The nested actions group is another flex container. The auto margin uses available space to separate the title from the actions. If the toolbar must remain usable on narrow screens, allow it to wrap or change its direction at a suitable breakpoint.

3. Align and distribute items

justify-content works along the main axis; align-items works along the cross axis. Their effect depends on flex-direction, not on fixed assumptions about horizontal and vertical directions.

.centered {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 12rem;
}

.spread {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

The first example centers children along both axes inside a box with a definite minimum height. Without available space on an axis, there may be no visible movement to distribute. align-self sets the cross-axis alignment for an individual item and overrides the container’s align-items for that item.

Common justify-content values include flex-start, flex-end, center, space-between, space-around, and space-evenly. Common align-items values include stretch, flex-start, flex-end, center, and baseline. For most interfaces, prefer gap for fixed spacing and alignment properties for distributing leftover space or aligning edges.

4. Understand flexible sizing

Flex item sizing uses three related values:

  • flex-basis is the starting size along the main axis before free space is distributed. It can be a length, percentage, or auto.
  • flex-grow controls how an item shares positive free space. A larger factor gets a larger share relative to the other grow factors.
  • flex-shrink controls how an item participates in reducing sizes when the line has insufficient space. Shrinking is weighted by the factors and base sizes.

The shorthand is flex: <grow> <shrink> <basis>. The card example’s flex: 1 1 14rem gives each card a 14rem starting basis, permits growth into spare space, and permits shrinking as the line gets tight. With wrapping enabled, the browser first forms lines; sizing is then resolved within each line.

/* Grow from a content or declared basis; shrink if needed. */
.item { flex: 1 1 12rem; }

/* Do not grow, but allow shrinking from a 16rem basis. */
.sidebar { flex: 0 1 16rem; }

/* Keep the item's basis size: neither grow nor shrink. */
.badge { flex: 0 0 5rem; }
Keyword Equivalent components Meaning
initial 0 1 auto Do not grow; allow shrinking from the automatic basis
auto 1 1 auto Allow growth and shrinking from the automatic basis
none 0 0 auto Neither grow nor shrink
1 Grow factor 1; basis effectively zero in the shorthand’s one-number form Share available main-axis space equally with other equally weighted items

The shorthand has defined defaults that can be easy to misread. Spell out all three values when exact behavior matters. Min-content constraints can also prevent an item from shrinking as far as expected; for a long string or wide child, try min-width: 0 on a row item (or the corresponding minimum size on the main axis) and decide how overflow should appear.

5. Flexbox or Grid?

Choose based on the relationship the design needs. MDN describes Flexbox as one-dimensional and Grid as two-dimensional; the W3C specification describes Flexbox as a box model optimized for user interface design. [MDN CSS layout; W3C Flexbox specification]

Need Good starting choice Reason
One row of controls or a vertical stack Flexbox Items relate along one primary direction
Cards that should flow and wrap naturally Flexbox Line wrapping is part of the desired behavior
Aligned rows and columns with coordinated tracks Grid Both dimensions matter to placement and sizing
Explicit placement across a two-dimensional area Grid Tracks and positions need joint control

These are starting points, not rigid rules. A page can use Grid for its main structure and Flexbox inside a toolbar, or the reverse. MDN’s layout cookbook has pattern-based examples.

6. Debug Flexbox in browser DevTools

  1. Select a suspected flex item in the Elements or Inspector panel, then move to its parent to confirm which element has display: flex.
  2. Check computed display, flex-direction, flex-wrap, gap, item basis, grow and shrink values, and minimum sizes. A crossed-out declaration may have lost the cascade.
  3. Turn on the browser’s flex layout overlay, when available, to see container boundaries, axes and item sizing. Names and controls vary by browser.
  4. Toggle one property at a time: change direction, disable wrapping, add a temporary outline, or adjust basis. Observe which axis changes.
  5. Check the parent’s available size and all ancestor constraints. Flexbox cannot distribute space that the container does not have.

MDN’s CSS debugging guide covers browser DevTools and compatibility information. The W3C CSS Flexible Box Layout Module Level 1 page found for this guide is a Candidate Recommendation Draft dated 14 October 2025; W3C cautions that the draft can be updated, replaced, or obsoleted, so it is not a final Recommendation. [W3C status and specification]

7. Common problems and fixes

Symptom Likely cause Fix to try
Items remain on one line and overflow Default flex-wrap is nowrap Set flex-wrap: wrap, or use flex-flow: row wrap
justify-content appears to do nothing No free space exists on the main axis, or the wrong axis is assumed Check container width/height, direction, and item sizes
Centering fails vertically or horizontally Alignment property was chosen by screen direction, or the container has no spare cross-axis size Identify main and cross axes; give the container enough size and use the matching alignment property
Long text forces a card wider than expected Automatic minimum size or unbreakable content prevents shrinking Try min-width: 0 on a row item; add overflow handling or wrapping for its content
Cards on the last wrapped row are wider Free space is distributed separately on each flex line Use Grid if all rows need coordinated columns; otherwise set a suitable basis or maximum width
Items appear in an unexpected order row-reverse, column-reverse, or an order value changes visual order Prefer source order that is meaningful; inspect both visual and keyboard reading order
Items refuse to shrink Minimum size, intrinsic content, fixed width, or child sizing constrains them Inspect min/max sizes and descendants; reduce the basis or minimum only if the content remains usable
Spacing seems larger than expected gap, margins, padding, or distributed free space are all contributing Temporarily disable each spacing source in DevTools, then keep the intended one
CSS declaration has no effect Another rule overrides it, selector misses, or declaration is invalid Inspect matched and computed styles, cascade order, and syntax

8. Performance, reliability, and cost

Flexbox is a native CSS layout method and requires no library or service. For ordinary interface layouts, focus on clear container boundaries, avoiding needless overrides, and checking behavior at narrow and wide sizes. If a page visibly jumps while loading, inspect changing content, font metrics, image dimensions, and scripts that alter the layout; Flexbox alone does not guarantee a stable page.

When documenting a layout issue, a screenshot can help show the viewport and resulting arrangement, but it cannot replace inspecting the DOM, computed styles, or responsive behavior. You can capture a page manually in a browser, or use ScreenshotNeo’s website screenshot API when you need repeatable page captures. Its API request can return PNG, JPEG, WebP, or PDF; the call below requests a screenshot of a page. See the ScreenshotNeo documentation for options and request details.

Or skip the browser setup

Use one GET request to capture a page. Store your API key securely and replace the example target URL if needed.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo accepts cookie or consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, with no card required.

9. FAQ

Can a flex item also be a flex container?

Yes. Apply display: flex to that item to lay out its own children. The outer container controls the item as a whole; the nested container controls its children.

Does gap work when Flexbox wraps?

Yes. It creates spacing between items and between flex lines. The resulting layout still sizes each line independently.

Should I use order to rearrange content?

Use it carefully. Visual order can differ from source and keyboard order, which can make an interface confusing. Prefer meaningful document order and use visual reordering only when it preserves a sensible reading and interaction sequence.

Where can I practice?

Start with MDN’s Flexbox learning guide. It also identifies an interactive Scrimba guide as a learning-partner resource.

References