Flexbox Fundamentals
Understand what Flexbox is for, how to turn any element into a flex container, and how the main axis and cross axis define the way flex items are laid out.
Before Flexbox, lining elements up in a row and having them share space nicely required floats, inline-block hacks, and a lot of guesswork. Flexbox is a layout mode built specifically for arranging items along a single line — either a row or a column — and distributing extra space between them. It's the tool you reach for any time you need a navbar, a button group, a card row, or anything that needs to align, center, or space itself out along one direction.
Flex Container vs Flex Item
Flexbox always involves two roles: a flex container (the parent element) and flex items (its direct children). You create a flex container by setting display: flex (or display: inline-flex) on an element. The instant you do that, every direct child of that element automatically becomes a flex item — you don't add any property to the children to opt them in.
This parent/child relationship matters a lot. Flexbox properties split into two groups: container properties (things like justify-content and flex-wrap) that you put on the parent to control the overall layout, and item properties (things like flex-grow and order) that you put on individual children to control how that one item behaves. Grandchildren — the children of flex items — are not flex items themselves unless you also give them display: flex.
• Flex container: the element with display: flex set on it • Flex item: any direct child of a flex container • Only direct children become flex items — nested elements are unaffected • A flex item can itself be a flex container for its own children
The Main Axis and the Cross Axis
This is the single most important idea in Flexbox, and the one beginners trip over most. Flexbox lays items out along two perpendicular axes: the main axis and the cross axis. The main axis is the primary direction items flow in. The cross axis runs perpendicular to it.
Which physical direction is 'main' and which is 'cross' is decided entirely by the flex-direction property. With the default flex-direction: row, the main axis runs horizontally (left to right) and the cross axis runs vertically (top to bottom). Switch to flex-direction: column, and the roles swap: the main axis now runs vertically, and the cross axis runs horizontally.
Why does this matter so much? Because almost every other Flexbox property is defined relative to these axes, not relative to literal 'horizontal' or 'vertical'. justify-content always aligns items along the main axis. align-items always aligns items along the cross axis. So in a row layout, justify-content controls horizontal spacing and align-items controls vertical alignment — but flip to a column layout, and suddenly justify-content controls vertical spacing while align-items controls horizontal alignment. Nothing about those properties changed; only the axis they operate on changed.
• Main axis: the direction set by flex-direction (row = horizontal, column = vertical) • Cross axis: always perpendicular to the main axis • justify-content aligns along the main axis • align-items aligns along the cross axis • Changing flex-direction swaps which physical direction each axis points in
Turning an element into a flex container
display: flex makes the container itself a block-level box that behaves like display: block from the outside display: inline-flex does the same, but the container behaves like display: inline-block from the outside — it won't force a line break No property is needed on the children — becoming a flex item is automatic
.container {
display: flex; /* or display: inline-flex; */
}Code Examples
Setting display: flex on .toolbar immediately arranges its child .icon-button elements in a horizontal row, side by side, with no floats or inline-block spacing quirks required. Expected result: Icon buttons sit next to each other in a single horizontal line.
By adding flex-direction: column, the main axis rotates to vertical. Menu items now stack top to bottom instead of side by side, and any justify-content on this container would now control vertical spacing rather than horizontal.
The <nav> is the flex container; each <button> is a flex item because it's a direct child. The <button> elements themselves are not flex containers, so their own text content lays out normally.
.toolbar {
display: flex;
}
.toolbar .icon-button {
padding: 8px 12px;
}.sidebar-menu {
display: flex;
flex-direction: column;
}<nav class="toolbar">
<button class="icon-button">Home</button>
<button class="icon-button">Search</button>
<button class="icon-button">Profile</button>
</nav>Main Axis vs Cross Axis (row direction)
With flex-direction: row (the default), items flow left to right along the main axis; align-items positions them up/down along the cross axis.
Main Axis ------------------------->
+------+ +------+ +------+
| Item | | Item | | Item |
+------+ +------+ +------+
^
Cross AxisImportant Rules
display: flex must be set on the parent; it has no effect if set on the element you're trying to lay out among its siblings
Only direct children become flex items — text nodes and deeply nested elements are unaffected
The default flex-direction is row, so the default main axis is horizontal
Every alignment property in Flexbox is relative to the main/cross axis, not to fixed 'left/right/top/bottom' directions
Where you'll use this immediately
Nearly every modern navigation bar, button group, form row, and card list on the web starts with a single display: flex declaration. Understanding the main/cross axis relationship up front means the rest of Flexbox — justify-content, align-items, wrapping, growing and shrinking — clicks into place quickly instead of feeling like memorized magic values..card-grid >.card { display: flex; }.card-grid { display: flex; }
Putting display: flex on the children instead of the parent makes each card its own tiny flex container, but does nothing to arrange the cards themselves in a row — that requires the parent to be the flex container..list { display: flex; flex-direction: column; } /* then trying to horizontally center items with... nothing, confusion follows */.list { display: flex; flex-direction: column; align-items: center; /* cross axis is now horizontal */ }
After switching to flex-direction: column, horizontal centering is a cross-axis job, so it belongs to align-items, not justify-content — a very common source of confusion.
[Predict the Output] A <div class="row"> has display: flex and flex-direction: column applied. If you then add justify-content: center to .row, what will visually happen to its children? A. The children will be centered horizontally B. The children will be centered vertically as a group within the container C. Nothing changes because justify-content only works with flex-direction: row D. The children will be centered on both axes simultaneously
B. The children will be centered vertically as a group within the container — With flex-direction: column, the main axis is vertical, and justify-content always operates on the main axis — so justify-content: center centers the group of children vertically, not horizontally.
Create a .profile-card flex container with flex-direction: column containing an avatar image, a name, and a bio. Then explain in a comment which axis is now vertical and which is horizontal..profile-card { display: flex; flex-direction: column; /* main axis: vertical, cross axis: horizontal */ }
Remember: flex-direction: column rotates the main axis to vertical, which also rotates the cross axis to horizontal.