๐ฆ 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: flexanddisplay: inline-flexfor a given layout need - Set the main axis with
flex-directionand predict how it changes other properties - Control wrapping with
flex-wrapand combine it using theflex-flowshorthand - Distribute items with
justify-contentand align them withalign-itemsandalign-content - Space items reliably with the
gapproperty 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.
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.
| Value | Container behaves like | Use when |
|---|---|---|
flex | a block โ full width, new line | The container is a section, header, or standalone strip |
inline-flex | inline-block โ only as wide as content, sits inline | You 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:
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.
| Value | Effect |
|---|---|
nowrap | All items on one line, even if they overflow (default) |
wrap | Items wrap onto new lines as needed |
wrap-reverse | Items 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.
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
- The header is a flex container with items vertically centered.
- The user-actions group sits against the right edge.
- 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-contentis main-axis andalign-itemsis cross-axis โ re-check them whenever you changeflex-direction. - Use
flex-flowwhen setting both direction and wrap; usegapfor spacing. - Reach for
margin-left: auto(ormargin-top: autoin 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-contentto work on a single, non-wrapping line. - Don't forget
flex-wrap: wrapwhen fixed-width items must reflow โ otherwise they overflow. - Don't lean on
row-reverse/column-reversefor 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-flexcreates a block-level or inline-level flex container.flex-directionsets the main axis;flex-wrapcontrols wrapping;flex-flowcombines both.justify-contentdistributes items on the main axis;align-itemsaligns them on the cross axis.align-contentdistributes wrapped lines โ and only matters with multiple lines and spare cross-axis space.gapspaces items between each other cleanly, with no outer-edge margin to manage.
๐ Further Reading
- MDN โ Basic concepts of Flexbox
- CSS-Tricks โ A Complete Guide to Flexbox
- MDN โ the gap property
๐ 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.