Skip to main content

๐Ÿ“ฆ Flex Container Properties

The flex container is where you set the rules that every item obeys. In this lesson we work through all seven container properties โ€” from the display declaration that starts it all to the gap property that spaces items cleanly โ€” with the exact behavior of each value and the patterns they enable.

๐ŸŽฏ Learning Objectives

By the end of this lesson, you will be able to:

  • Choose between display: flex and display: inline-flex for a given layout need
  • Set the main axis with flex-direction and predict how it changes other properties
  • Control wrapping with flex-wrap and combine it using the flex-flow shorthand
  • Distribute items with justify-content and align them with align-items and align-content
  • Space items reliably with the gap property instead of margins

Estimated Time: 30โ€“40 minutes  โ€ข  Difficulty: Intermediate

Hands-on: Build a three-part header โ€” logo, nav, user actions โ€” using only container properties.

In This Lesson

The Container Property Map

In the previous lesson you learned the Flexbox model โ€” container, items, and the two axes. Now we focus entirely on the container: the parent element with display: flex. Its properties decide the direction items flow, whether they wrap, and how free space is distributed on both axes.

flowchart TD A[Flex container properties] --> B[display] A --> C[flex-direction] A --> D[flex-wrap] A --> E[flex-flow] A --> F[justify-content] A --> G[align-items] A --> H[align-content] A --> I[gap]

A useful way to remember them: display turns it on, flex-direction/flex-wrap set the flow, the three justify-*/align-* properties handle alignment, and gap handles spacing.

display: flex vs inline-flex

The display property is what creates the flex container in the first place. It has two flavors that differ only in how the container itself behaves in the surrounding document flow โ€” not in how the items inside are laid out.

ValueContainer behaves likeUse when
flexa block โ€” full width, new lineThe container is a section, header, or standalone strip
inline-flexinline-block โ€” only as wide as content, sits inlineYou want several flex groups to sit side by side within a line of text or content
/* Block-level flex container */
.container {
  display: flex;
}

/* Inline-level flex container */
.badge-group {
  display: inline-flex;
}

Reach for flex for a main navigation bar that spans a header; reach for inline-flex for a small group of related buttons or badges that should flow inline with other content.

flex-direction

The flex-direction property sets the main axis โ€” the direction items are placed and the meaning of "start" and "end". It takes four values:

The four flex-direction values Row places items left to right, row-reverse right to left, column top to bottom, column-reverse bottom to top. row 1 2 3 row-reverse 3 2 1 column 1 2 3 column-reverse 3 2 1
Figure 1 โ€” The four flex-direction values. The row variants keep a horizontal main axis; the column variants make it vertical.
.container { flex-direction: row; }            /* left to right (default) */
.container { flex-direction: row-reverse; }    /* right to left */
.container { flex-direction: column; }         /* top to bottom */
.container { flex-direction: column-reverse; } /* bottom to top */

โš ๏ธ Direction changes everything downstream

Because justify-content always works on the main axis and align-items on the cross axis, switching to column swaps what those two do. And the -reverse variants change visual order only โ€” the DOM order (and therefore tab and screen-reader order) stays the same, which can hurt accessibility if you rely on it for meaningful sequencing.

A classic responsive move is stacking a nav vertically on mobile and switching it to a row on wider screens:

/* Mobile first: stacked */
.nav { display: flex; flex-direction: column; }

/* Wider screens: horizontal */
@media (min-width: 768px) {
  .nav { flex-direction: row; }
}

flex-wrap & flex-flow

By default, flex items are forced onto a single line and will shrink (or overflow) rather than wrap. The flex-wrap property changes that โ€” it is the key to responsive layouts that reflow when space runs out.

ValueEffect
nowrapAll items on one line, even if they overflow (default)
wrapItems wrap onto new lines as needed
wrap-reverseItems wrap onto new lines, but new lines appear above (for rows)
.gallery {
  display: flex;
  flex-wrap: wrap;   /* fixed-width tiles reflow to new rows automatically */
  gap: 1rem;
}

The flex-flow property is a shorthand that sets flex-direction and flex-wrap together. The first value is the direction, the second is the wrap:

/* flex-direction: row; flex-wrap: wrap; */
.container { flex-flow: row wrap; }

/* flex-direction: column; flex-wrap: nowrap; */
.container { flex-flow: column nowrap; }

โœ… Responsive without media queries

Combine flex-wrap: wrap with items that have a flexible basis (flex: 1 0 300px) and the layout adapts to any width on its own โ€” cards fill a row, then drop to the next line when they no longer fit, no breakpoint required.

justify-content

justify-content distributes items along the main axis and controls what happens to leftover free space. It is the property you use to center a row, push items apart, or space them evenly.

The six justify-content values Diagrams showing flex-start, center, flex-end, space-between, space-around, and space-evenly distributions of three items. flex-start center flex-end space-between space-around
Figure 2 โ€” How justify-content spreads three items across the main axis. space-evenly (not shown) makes every gap, including the edges, exactly equal.
.container { justify-content: flex-start; }    /* packed at the start (default) */
.container { justify-content: center; }        /* centered */
.container { justify-content: flex-end; }      /* packed at the end */
.container { justify-content: space-between; } /* first/last at edges, gaps between */
.container { justify-content: space-around; }  /* equal space around each item */
.container { justify-content: space-evenly; }  /* every gap, including edges, equal */

๐Ÿ“– The three "space" values, precisely

space-between: no space at the outer edges; all free space goes between items.

space-around: each item gets equal space on both sides, so edge gaps are half the size of the gaps between items.

space-evenly: every gap โ€” including the two edges โ€” is identical.

A frequent alternative to justify-content for "logo left, actions right" layouts is an auto margin on one item: margin-left: auto absorbs all the free space and pushes that item to the end. You'll use exactly that in this lesson's exercise.

align-items & align-content

These two are easy to confuse, so pin down the difference now: align-items aligns items within a line on the cross axis; align-content distributes multiple lines when the container has wrapped.

align-items โ€” cross-axis alignment of items

This is how you get vertical centering in a row layout. Its values mirror justify-content but on the cross axis, plus two special ones:

.container { align-items: stretch; }     /* items fill the cross size (default) */
.container { align-items: flex-start; }  /* aligned to cross start */
.container { align-items: center; }      /* centered on the cross axis */
.container { align-items: flex-end; }    /* aligned to cross end */
.container { align-items: baseline; }    /* text baselines line up */

The baseline value is handy when items contain text at different sizes โ€” it lines the type up along the reading baseline rather than the box edges. And the celebrated perfect-centering recipe is simply:

.hero {
  display: flex;
  justify-content: center;  /* horizontal (main axis)  */
  align-items: center;      /* vertical (cross axis)   */
  min-height: 100vh;
}

align-content โ€” distributing wrapped lines

align-content only does something when there are multiple lines (so flex-wrap: wrap is on) and the container is taller than the lines need. It accepts flex-start, center, flex-end, space-between, space-around, and stretch (the default).

โš ๏ธ Why isn't align-content doing anything?

Two common causes: the container isn't wrapping (only one line exists), or the container has no extra cross-axis space for the lines to move within. Add flex-wrap: wrap and give the container a fixed height taller than its content, and align-content springs to life.

The gap Property

The gap property (with its longhands row-gap and column-gap) puts consistent space between flex items without adding space around the outer edges. It is the modern replacement for margins-on-every-child and is well supported in all current browsers.

/* Same gap in both directions */
.container { gap: 1rem; }

/* row-gap then column-gap */
.container { gap: 1rem 2rem; }

/* Individually */
.container { row-gap: 1rem; column-gap: 2rem; }

โœ… Why gap beats margins

  • No leftover margin on the first/last item to strip off.
  • Space appears only between items, never on the container's outer edge.
  • One declaration to change spacing everywhere โ€” no :not(:last-child) selectors.

Here's a responsive dashboard grid that leans on wrap plus gap:

.dashboard {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.widget {
  flex: 1 1 250px;   /* grow, shrink, min basis 250px */
}

Hands-on: A Three-Part Header

๐Ÿ‹๏ธ Logo ยท Nav ยท User actions

Objective: Build a site header with a logo on the left, navigation links next to it, and user actions pinned to the right โ€” using only container properties (and one auto margin).

Requirements

  1. The header is a flex container with items vertically centered.
  2. The user-actions group sits against the right edge.
  3. On screens narrower than 768px, the header stacks vertically.
๐Ÿ’ก Hint

Use align-items: center to line everything up vertically. To push the actions right, give that group margin-left: auto. For the responsive stack, flip flex-direction to column inside a media query and reset the auto margin.

โœ… Sample solution
<header class="site-header">
  <div class="logo">MyApp</div>
  <nav class="primary-nav">
    <a href="#">Home</a>
    <a href="#">Products</a>
    <a href="#">About</a>
  </nav>
  <div class="user-actions">
    <a href="#">Log in</a>
    <a href="#">Profile</a>
  </div>
</header>
.site-header {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 0.75rem 1.5rem;
  background: #1e293b;
  color: #fff;
}

.primary-nav,
.user-actions {
  display: flex;
  gap: 1rem;
}

.user-actions {
  margin-left: auto;   /* push actions to the right edge */
}

@media (max-width: 768px) {
  .site-header { flex-direction: column; align-items: stretch; }
  .user-actions { margin-left: 0; }
}

Every visible arrangement here comes from container properties plus one auto margin โ€” no positioning, no floats.

๐ŸŽฏ Quick Quiz

Question 1: Which property distributes flex items along the main axis?

Question 2: Your align-content declaration has no visible effect. What is the most likely reason?

Question 3: Why is gap generally preferred over margins for spacing flex items?

Best Practices & Pitfalls

โœ… Do

  • Remember that justify-content is main-axis and align-items is cross-axis โ€” re-check them whenever you change flex-direction.
  • Use flex-flow when setting both direction and wrap; use gap for spacing.
  • Reach for margin-left: auto (or margin-top: auto in columns) to split a bar into start/end groups.
  • Test each breakpoint; a header that looks perfect on desktop may overflow on mobile.

โš ๏ธ Don't

  • Don't expect align-content to work on a single, non-wrapping line.
  • Don't forget flex-wrap: wrap when fixed-width items must reflow โ€” otherwise they overflow.
  • Don't lean on row-reverse/column-reverse for meaningful order; they change visuals only and can desync from keyboard and screen-reader order.
  • Don't nest flex containers deeper than the design needs โ€” each new container is another context to reason about.

Summary & Quiz

๐ŸŽ‰ Key Takeaways

  • display: flex / inline-flex creates a block-level or inline-level flex container.
  • flex-direction sets the main axis; flex-wrap controls wrapping; flex-flow combines both.
  • justify-content distributes items on the main axis; align-items aligns them on the cross axis.
  • align-content distributes wrapped lines โ€” and only matters with multiple lines and spare cross-axis space.
  • gap spaces items between each other cleanly, with no outer-edge margin to manage.

๐Ÿ“š Further Reading

๐Ÿš€ What's Next?

Container properties decide the overall flow. Next we flip to the other side of the relationship โ€” the item properties (flex-grow, flex-shrink, flex-basis, align-self, and order) โ€” that let individual children size and place themselves.

๐ŸŽ‰ Container mastered!

You can now shape any single-axis strip. Let's give the items a voice of their own.