CSS Flexbox generator
Build a flex container by eye and copy the code: direction, wrapping, justify-content, align-items, align-content and gap, plus flex-grow, flex-shrink, flex-basis, align-self and order on any item, with only the properties you changed in the output.
Container
Main axis: horizontal. Cross axis: vertical.
nowrap forces every item onto one line, however narrow it gets.
Spare space along the main axis (horizontal).
Every item on its line, across the cross axis (vertical).
The lines of a wrapped container, as blocks.
Items
Numbered in source order. 4 of 12 items. Only the items you change get a rule of their own.
Share of the spare space this item takes. 0 means it does not grow.
How much it gives up when the items overflow. 0 means it refuses.
The starting main size, before growing or shrinking. auto defers to width or height.
auto means whatever align-items on the container says.
Moves the item visually only. Reading and tab order stay in source order.
Preview
The items carry different amounts of padding so the alignment values have something to show, and the box holds a minimum height so the cross axis has room. That is the preview's own styling; the code below is only the flex properties.
Generated code
.flex-container {
display: flex;
}<div class="flex-container"> <div class="flex-item">1</div> <div class="flex-item">2</div> <div class="flex-item">3</div> <div class="flex-item">4</div> </div>
4 items. Editing item 1.
Build a flex container by eye and copy the code: direction, wrapping, justify-content, align-items, align-content and gap, plus flex-grow, flex-shrink, flex-basis, align-self and order on any item, with only the properties you changed in the output.
On this page
How to use this tool#
- Set the container. Pick
flexorinline-flex, then work down the list: direction, wrapping, the two alignment properties and the gaps. The preview redraws on every change. - Add or remove items until the preview looks like the layout you are building. Items are numbered in source order, so the numbers stay put when
orderor a reverse direction moves them on screen. - Pick an item number, then edit that item. The numbered buttons choose which item the
flex-grow,flex-shrink,flex-basis,align-selfandorderfields apply to. - Read the two output boxes. The CSS carries the container rule plus one rule for each item you actually changed, and the HTML carries the matching classes. Both have a copy button.
- Two switches change the output, not the layout. Turning off "Use the flex shorthand" writes
flex-grow,flex-shrinkandflex-basisseparately. Turning on "Include container defaults" writes every container property, including the ones still at their initial value, which is useful when you want the full picture in front of you.
By default the generator prints only what differs from the browser's own defaults, so the rule you copy is the shortest one that produces the preview.
What flexbox is for#
Flexbox lays out a row or a column of boxes and shares the leftover space between them. You setdisplay: flex on a parent, and its direct children become flex items: they line up along one axis, they can grow into spare space, they can shrink when there is not enough, and they can be aligned as a group or one at a time.
That is the whole model. It is a one-dimensional layout method, and MDN draws the line with grid exactly there: "flexbox was designed for layout in one dimension, either a row or a column. Grid was designed for two-dimensional layout, rows, and columns at the same time."
Only direct children become flex items. Text directly inside the container is wrapped in an anonymous flex item, and a child's own children are laid out however that child says.
Main axis and cross axis#
Every flexbox question comes back to which axis you are talking about. The main axis is the one the items line up along, and flex-direction chooses it. The cross axis is the other one, always at right angles to it.
rowandrow-reverse: the main axis runs across, the cross axis down.columnandcolumn-reverse: the main axis runs down, the cross axis across.
Once you know which is which, the property names sort themselves out:
justify-contentworks on the main axis, on the group of items as a whole.align-itemsworks on the cross axis, on each item individually.align-contentworks on the cross axis, on whole lines, and only when there are several.
/* Main axis across, cross axis down. */
.row {
display: flex;
flex-direction: row;
justify-content: space-between; /* left to right */
align-items: center; /* top to bottom */
}
/* The same two properties, both axes turned a quarter. */
.column {
display: flex;
flex-direction: column;
justify-content: space-between; /* top to bottom */
align-items: center; /* left to right */
}The reverse directions do not rotate anything. The spec defines row-reverse as "same as row, except the main-start and main-end directions are swapped", so the axis still runs across; it is the start and end that trade places. That is why justify-content: flex-start pushes items to the right in a row-reverse container.
The container properties#
Six properties plus the gaps, and the generator above writes every one of them. The value in brackets is the initial one, which is what the browser uses when you leave the property out.
- display (
flexorinline-flex): makes the box a flex container.inline-flexis identical inside; the difference is outside, where the box sits in the line like an image instead of taking the full width. Its children behave the same either way. - flex-direction (
row): picks the main axis, as above. - flex-wrap (
nowrap): by default items never wrap. They shrink, and when they cannot shrink any further they overflow.wraplets them start a new line;wrap-reversedoes the same but swaps cross-start and cross-end, so new lines stack upwards in a row container, andalign-items: flex-startthen aligns towards what used to be the bottom. - justify-content (
normal, which behaves asflex-start): shares the spare main-axis space.space-betweenputs the first and last item against the edges,space-aroundgives each item an equal margin so the outer gaps are half the inner ones, andspace-evenlymakes every gap the same, edges included. - align-items (
normal, which behaves asstretch): sets the cross-axis alignment of every item.stretchis why flex items in a row come out the same height by default: each one stretches to the height of its line, unless it has a height of its own. - align-content (
normal, which behaves asstretch): aligns the lines. See the next section for why it so often appears to do nothing. - gap, row-gap and column-gap (
normal, which computes to zero in a flex container): the space between items, and between lines. It is real spacing, not a margin, so it never appears outside the first or last item.
align-items or align-content?#
This is the most common flexbox confusion, and the rule is short.align-items moves the items inside their line. align-content moves the lines inside the container. A container that does not wrap has exactly one line, and the spec says plainly: "this property has no effect on a single-line flex container".
The reason is in the same section: "only multi-line flex containers ever have free space in the cross-axis for lines to be aligned in, because in a single-line flex container the sole line automatically stretches to fill the space". So align-content needs three things together to show anything: flex-wrap: wrap, enough items that they actually wrap onto more than one line, and a container taller than those lines need. Set any one of them short and the property sits there doing nothing. The generator flags this case under the control.
The item properties#
These go on the children, not on the container. An item you have not touched behaves as flex: 0 1 auto: it does not grow, it does shrink, and its starting size comes from its content.
- flex-grow (
0): how much of the leftover main-axis space this item takes, as a share of all the grow values. Two items at1split it in half; at2and1the first takes two thirds of the leftover. - flex-shrink (
1): the same idea when the items are too big for the line, weighted by each item's base size.0means "never give anything up", which is how you keep an icon or a fixed sidebar at its size. - flex-basis (
auto): the size an item starts from, before any growing or shrinking. - align-self (
auto): overridesalign-itemsfor this one item.automeans "use whatever the parent says". - order (
0): moves the item visually. Items are laid out in order value first, source order second, and negative values are allowed, soorder: -1pulls an item to the front without touching the other items.
order comes with a warning attached. The spec is explicit: "authors must use order only for visual, not logical, reordering of content. Style sheets that use order to perform logical reordering are non-conforming." It does not change the document, so screen readers read the source order and the Tab key still follows it. An item you moved to the front with order is still the fourth stop on the keyboard.
The flex shorthand, and what flex: 1 expands to#
flex sets the three sizing longhands at once, and it is the form you should write: when you use the shorthand, any part you leave out is reset, which is nearly always what you meant. The defaults inside the shorthand are deliberately different from the property defaults.
.item { flex: 1; } /* 1 1 0% grow, shrink, start from nothing */
.item { flex: auto; } /* 1 1 auto grow and shrink, start from the content */
.item { flex: initial; } /* 0 1 auto the default: shrink only */
.item { flex: none; } /* 0 0 auto never grow, never shrink */
.item { flex: 2 1 12rem; } /* all three, written out */The one to remember is flex: 1. A bare number sets flex-grow, and the other two fill in as 1 and 0%, giving flex: 1 1 0%. That zero basis is the whole point: every item starts from nothing, so the space is shared out from scratch and equal grow values produce equal sizes. Write flex: auto instead and each item starts from its content, so the leftover is shared equally but the finished sizes are not.
The generator above uses the shorthand by default and prints the shortest correct form: none and auto where they fit, a bare number when the basis is 0%, and all three values otherwise. Turn the switch off to see the longhands.
flex-basis and width are not the same thing#
flex-basis sizes along the main axis. width and height size along the physical axes and do not move when the direction does. In a row container flex-basis plays the part of width; in a column container it plays the part of height.
When both are set, flex-basis wins on the main axis, unless it is auto. That is what auto means here: the spec says it "retrieves the value of the main size property as the used flex-basis", and if that is itself auto, the used value is content, which is the item's content size.
.card {
width: 400px;
flex-basis: 200px;
}
/* Along the main axis the used size starts at 200px. width is ignored,
because flex-basis is not auto. In a column container the same
flex-basis would override height instead, and width would apply. */Two practical consequences. In a column container, a percentage flex-basis resolves against the container's height, so it needs a definite height to resolve against or it falls back to the content size. And width is still worth setting alongside a non-auto basis, because it applies on the cross axis in a column container and it is what a non-flex fallback would use.
Why your flex item will not shrink#
A long URL, a wide table or a white-space: nowrap label inside a flex item pushes the row wider than its container, and flex-shrink appears to be ignored. It is not. The culprit is a rule flexbox added to min-width and min-height, whose initial value is auto. From the spec: "the used value of a main axis automatic minimum size on a flex item whose computed overflow value is non-scrollable is its content-based minimum size; for scroll containers the automatic minimum size is zero, as usual."
In other words, by default a flex item refuses to shrink below the size its content needs, and that floor beats flex-shrink. There are two ways out, and the sentence above names both: give the item a real min-width: 0 (or min-height: 0 in a column container), or make it a scroll container with overflow: hidden, auto orscroll.
.item {
flex: 1;
min-width: 0; /* or overflow: hidden, if the item scrolls or clips */
}
/* Without it, a long unbroken string or a nowrap label keeps the item
at its content width and pushes the row wider than the container. */
.item .label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}The same trap in a column direction is min-height: auto, and it is why nested flex columns overflow the page instead of scrolling: every level holds its content's height as a floor. Adding min-height: 0 to the intermediate columns is the standard fix.
Patterns worth keeping#
Centring, in two lines
One container, one value on each axis. It works whatever the size of the thing inside, and it does not care whether the content is text, an image or another layout.
.centre {
display: flex;
justify-content: center; /* main axis */
align-items: center; /* cross axis */
min-height: 100vh;
}A navigation bar
A logo on the left, links on the right, everything on one baseline. The interesting part is the auto margin: a flex item with margin-inline-start: auto absorbs all the spare space on that side before justify-content ever sees it, which is a cleaner way to split a bar into groups than adding a spacer element.
.nav {
display: flex;
align-items: center;
gap: 1.5rem;
}
/* An auto margin swallows all the spare space on that side, so the
links sit hard right without touching justify-content. */
.nav-links {
margin-inline-start: auto;
}Equal columns
.columns {
display: flex;
gap: 1rem;
}
/* flex: 1 is 1 1 0%: every column starts from zero, so they end up
the same width whatever they contain. Use flex: auto instead to
let the content decide the share. */
.columns > * {
flex: 1;
}If one column holds a long word or a code block, add min-width: 0 to the children as well, for the reason in the previous section.
A footer that stays at the bottom
The classic sticky footer: a full-height column where the middle region takes whatever is left. No absolute positioning, and the footer drops below the fold as soon as the content is long enough.
body {
display: flex;
flex-direction: column;
min-height: 100svh;
margin: 0;
}
/* The main region takes every pixel the header and footer leave. */
body > main {
flex: 1;
}Cards that wrap
.cards {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
/* Start at 16rem, wrap when the line is full, then share out what is
left on each line. The last line stretches its cards wider than the
ones above it; CSS Grid with auto-fill is the fix if that matters. */
.cards > * {
flex: 1 1 16rem;
}This is the pattern where flexbox and grid genuinely differ. Flexbox fills each line and then stretches the last one, because it only knows about the line it is on. grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)) keeps every card the same width instead. Pick by whether a ragged last row is a feature or a bug for you. The CSS Grid generator builds that version.
Flexbox or grid?#
They are not rivals, and most pages use both. MDN's test is one question: "do we only need to control the layout by row or column? If yes, use flexbox. Do we need to control the layout by row and column? If yes, use grid layout."
The other half of the distinction is where the sizes come from. Again from MDN: "flexbox works from the content out", letting the size of each item decide how much space it takes, while "grid works from the layout in", where you define the tracks first and place items into them. A toolbar, a form row, a list of tags and a sticky footer are content-out problems. A page skeleton, a photo gallery on a fixed rhythm and anything that has to line up in both directions are layout-in problems.
Note that gap works in both, and so do justify-content, align-items and align-content, because they belong to CSS Box Alignment rather than to either layout method. What you learn here carries over. place-items is the one shorthand to be careful with: its second value is justify-items, which does nothing in flexbox, so only the first half has any effect.
Browser support#
Flexbox itself is not a question any more. Every current browser has supported the unprefixed final syntax since around 2015, and MDN lists the flex properties as widely available. The old prefixed and 2009 syntaxes only matter on browsers nobody is building for now. Internet Explorer's implementation stopped at an older draft and carries a long list of known bugs, which is what the community's Flexbugs catalogue was written for.
gap in a flex container is the one piece that arrived late, well after it worked in grid:
- Firefox 63, October 2018
- Chrome 84 and Edge 84, July 2020
- Safari 14.1 and iOS Safari 14.5, April 2021
A browser without it ignores the declaration silently, so the items simply sit with no space between them. If you still support Safari 14.0 or older, the fallback is a margin on every item but the first, behind a feature query. Note that gap is one property shared with grid and multi-column, so a plain @supports (gap: 1rem) can report true on a browser that only implements it for grid. In practice the browsers that were in that gap are old enough that the margin fallback below is usually not worth writing at all.
.row {
display: flex;
gap: 1rem;
}
/* Only worth writing for Safari below 14.1 and iOS below 14.5. */
@supports not (gap: 1rem) {
.row > * + * {
margin-inline-start: 1rem;
}
}Nothing here leaves your browser#
The preview is real CSS applied to real elements on this page, and the code is assembled in your browser from the values you picked. Nothing is uploaded, nothing is stored and there is no backend to send it to. Go offline and the tool keeps working.
Questions people ask#
How do I centre a div with flexbox?
display: flex on the parent, then justify-content: center and align-items: center. The parent needs a height for the vertical half to have anything to work with, which is whatmin-height: 100vh does in the example above. Do not reach for place-content: center as a shortcut: it sets justify-content and align-content, and align-content does nothing on a single-line container, so the cross axis is left uncentred.
What is the difference between flex: 1 and flex: auto?
flex: 1 is 1 1 0% and flex: auto is 1 1 auto. Both grow and shrink; they disagree about the starting size. With flex: 1 every item starts at zero, so the space is divided evenly and the items end up the same size. With flex: auto each item starts at its content size and the leftover is divided evenly, so a longer item stays longer.
Why is align-content doing nothing?
Because the container has one line. It needs flex-wrap: wrap, enough items to actually wrap, and spare height for the lines to move in. If you want to move the items rather than the lines, the property you want is align-items.
Why does my item ignore its width?
Either a flex-basis other than auto is overriding it on the main axis, or the item is growing or shrinking away from it. An item with flex-grow set will pass its width; an item with the default flex-shrink: 1 will fall below it when the line is tight.flex: 0 0 auto keeps an item at exactly the size you gave it.
Can I use gap with flexbox?
Yes, in every browser released since April 2021. Before that Safari supported gap in grid but not in flexbox, which is where the property's reputation for being unreliable comes from.
Does order change the tab order?
No. order changes only the visual order. Keyboard focus and screen reader reading order follow the document, so reordering items visually can leave the page working in one sequence and reading in another. Where the visual order is the right order, change the HTML.
Do the generated classes have to be called that?
No. flex-container and flex-item are just names so the CSS and the HTML match when you copy both. Rename them to whatever your project uses; nothing in the output depends on the names.
Why is the CSS shorter than I expected?
Because a property set to its own initial value has no effect and is left out. The output is the minimum that reproduces the preview. Tick "Include container defaults" to see the full set of container properties written out, which is useful when you are overriding a rule that already sets them.
Related tools
Build a CSS Grid layout visually: set the columns, rows, track sizes and gaps, drag items across cells to place them, and copy the generated CSS and the matching HTML.
Work out a fluid clamp() declaration from a size at two viewport widths, with the slope and intercept shown, a live preview at any width, a type scale in custom properties and a check that the text still resizes.
Build linear, radial and conic CSS gradients visually: any angle, shape, size and centre, colour stops with their own position and opacity, repeating variants and an interpolation colour space, with the background declaration ready to copy.
Build a CSS box-shadow visually, with as many layers as you need: offsets, blur, spread, colour with opacity and inset, over a preview whose box colour, background and border radius you set yourself.