DEV Community

Michael Lip
Michael Lip

Posted on • Originally published at zovo.one

Flexbox Cheat Sheet: The Properties That Actually Matter

I'll be honest. I've been writing CSS professionally for years and I still pause when I need to vertically center something with Flexbox. Not because the syntax is hard -- align-items: center -- but because I can never remember whether align-items is the cross axis or the main axis, and which axis is which depends on the flex direction. The mental model has a learning curve that the simplicity of the syntax hides.

So here's the reference I wish I'd had when I started. Not the spec. Not the comprehensive guide. Just the parts that solve actual layout problems.

The two axes

Everything in Flexbox revolves around two axes:

  • Main axis: the direction items flow. Set by flex-direction.
  • Cross axis: perpendicular to the main axis.
/* Main axis: horizontal (left to right) */
flex-direction: row;

/* Main axis: vertical (top to bottom) */
flex-direction: column;
Enter fullscreen mode Exit fullscreen mode

Once you know which axis is which, the property names make sense:

  • justify-content aligns items along the main axis
  • align-items aligns items along the cross axis

When flex-direction is row (the default), justify-content is horizontal and align-items is vertical. When flex-direction is column, they swap. This swap is the source of nearly all Flexbox confusion.

The centering patterns

Centering is Flexbox's most famous use case. Here are the three patterns:

/* Center horizontally (row direction) */
.container {
  display: flex;
  justify-content: center;
}

/* Center vertically (row direction) */
.container {
  display: flex;
  align-items: center;
}

/* Center both */
.container {
  display: flex;
  justify-content: center;
  align-items: center;
}
Enter fullscreen mode Exit fullscreen mode

For the "center both" case, there's a shorter alternative using Grid (display: grid; place-items: center), but Flexbox is the standard approach.

Space distribution

justify-content has several values for distributing space between items:

/* Items packed to the start */
justify-content: flex-start;

/* Items packed to the end */
justify-content: flex-end;

/* Items centered, no space at edges */
justify-content: center;

/* Equal space between items, none at edges */
justify-content: space-between;

/* Equal space around items (half-size at edges) */
justify-content: space-around;

/* Equal space everywhere including edges */
justify-content: space-evenly;
Enter fullscreen mode Exit fullscreen mode

In practice, space-between is the one I use most. It's the pattern for a navbar where the logo is on the left and the menu is on the right:

.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
Enter fullscreen mode Exit fullscreen mode

Two children, one pushed to each side, vertically centered. This replaces the old float: left / float: right pattern entirely.

The flex shorthand

The flex property on child items is shorthand for three values:

flex: <flex-grow> <flex-shrink> <flex-basis>;
Enter fullscreen mode Exit fullscreen mode
  • flex-grow: how much the item should grow relative to siblings when there's extra space. 0 means don't grow.
  • flex-shrink: how much the item should shrink when there's not enough space. 1 means shrink proportionally.
  • flex-basis: the initial size before growing or shrinking. Like a starting width (or height in column direction).

The values that matter:

/* Don't grow, don't shrink, use auto width */
flex: 0 0 auto;   /* same as flex: none */

/* Grow to fill space, shrink if needed, start from 0 */
flex: 1 1 0;      /* same as flex: 1 */

/* Grow to fill space, start from auto width */
flex: 1 1 auto;   /* same as flex: auto */
Enter fullscreen mode Exit fullscreen mode

flex: 1 on all children makes them share space equally. flex: none on an element makes it rigid -- it won't grow or shrink.

The classic sidebar layout:

.layout {
  display: flex;
}

.sidebar {
  flex: 0 0 250px;  /* fixed 250px width */
}

.main {
  flex: 1;  /* takes remaining space */
}
Enter fullscreen mode Exit fullscreen mode

The gap property

Before gap existed in Flexbox, spacing items required margins with a negative margin hack on the container, or using :last-child selectors to remove the trailing margin. gap solved this cleanly:

.container {
  display: flex;
  gap: 16px;
}
Enter fullscreen mode Exit fullscreen mode

This puts 16px between every item but not before the first or after the last. You can also set row and column gaps separately with row-gap and column-gap, though this mainly matters when items wrap.

Wrapping

By default, flex items try to fit on one line. flex-wrap: wrap allows them to flow to the next line:

.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
Enter fullscreen mode Exit fullscreen mode

When items wrap, align-content controls how the wrapped lines are distributed along the cross axis. It accepts the same values as justify-content (center, space-between, etc.). align-items still controls alignment within each line; align-content controls the lines themselves.

This distinction between align-items and align-content is another common source of confusion. If you're not wrapping, align-content has no effect.

Order and visual reordering

The order property changes the visual order of items without changing the DOM order:

.item-first {
  order: -1;  /* moves to the beginning */
}

.item-last {
  order: 99;  /* moves to the end */
}
Enter fullscreen mode Exit fullscreen mode

This is useful for responsive layouts where the visual order should differ on mobile vs desktop. But use it sparingly -- screen readers follow the DOM order, not the visual order. If the order matters for understanding the content, change the DOM instead.

Five common Flexbox mistakes

  1. Using align-items: stretch without realizing it's the default. If your flex items are unexpectedly stretching to fill the container's height, that's align-items: stretch in action. Set it to flex-start if you want items at their natural height.

  2. Forgetting min-width: 0 for truncated text. By default, flex items won't shrink below their content's minimum size. If you have a long text string with text-overflow: ellipsis, it won't truncate because the flex item refuses to shrink past the text length. Adding min-width: 0 to the flex item overrides this.

  3. Using flex-direction: column and wondering why justify-content: center doesn't center horizontally. It doesn't because in column direction, justify-content is vertical. Use align-items: center for horizontal centering in column direction.

  4. Nesting flex containers unnecessarily. Not every child layout needs its own display: flex. Sometimes a child just needs margin-left: auto to push itself to the end of the main axis.

  5. Not using flex-shrink: 0 on fixed-width elements. If you want a sidebar to stay at exactly 250px, you need flex: 0 0 250px. Without flex-shrink: 0, the sidebar can shrink below 250px on narrow viewports.

For building Flexbox layouts visually and seeing how each property affects the result, I put together a Flexbox generator at zovo.one/free-tools/flexbox-generator that lets you toggle properties and copy the CSS.

Flexbox has been stable for years now, and it remains the right tool for one-dimensional layout. Master the two axes, understand the flex shorthand, use gap for spacing, and you've got 90% of what you need. The rest is reference material you look up when you need it.


I'm Michael Lip. I build free developer tools at zovo.one. 350+ tools, all private, all free.

Top comments (0)