Centre an element with flexbox and no wrapper markup
Canonical URL: https://devexamples.com/css/center-an-element-with-flexbox/
The problem
A call-to-action band needs its heading, note and button centred as one stack inside a tall section, and the usual first attempt adds a wrapper div to hold the extra rules. The section already exists, so nothing should be added to the markup. The same rules also have to survive a short viewport, where centred content can end up taller than the box that centres it. Current browsers assumed.
Short answer
Put display: flex on the container the content already has, pick the direction that decides which axis is which, use align-items on the cross axis and justify-content on the main axis, and give the container a min-block-size so there is leftover space to distribute.
Centring is a conversation between a container and the space it has left over, which is why it fails so often in a container that never claimed any space to begin with. Flexbox resolves it with two properties on the element that already wraps the content, so no extra div is needed and the markup stays as the document structure wants it.
<section class="cta">
<h2 class="cta-title">Find the answer once, then reuse it</h2>
<p class="cta-note">Every example ships with the code and the reasoning behind it.</p>
<a class="cta-action" href="/search/">Browse the corpus</a>
</section>.cta {
display: flex;
flex-direction: column;
align-items: center; /* cross axis: horizontal, because the main axis is vertical */
justify-content: center; /* main axis: vertical */
gap: 1rem;
min-block-size: 60dvh;
padding: 2rem 1.5rem;
text-align: center;
}/* A row rather than a column: the properties keep their names, the axes swap. */
.toolbar {
display: flex;
align-items: center; /* vertical, because the main axis is horizontal */
gap: 0.75rem;
}
.toolbar-action {
margin-inline-start: auto; /* one item pushed to the far end, no absolute position */
}
/* Content that may outgrow its box: auto margins centre without hiding an edge. */
.dialog-body {
display: flex;
overflow: auto;
max-block-size: 30dvh;
}
.dialog-body > .dialog-panel {
margin: auto;
}
/* Wrapped lines are not items: align-content positions the lines themselves. */
.tag-cloud {
display: flex;
flex-wrap: wrap;
align-content: center;
align-items: center;
gap: 0.5rem 0.75rem;
min-block-size: 12rem;
}Explanation
Both properties distribute leftover space, and neither of them means anything until the container has some. That is the entire reason min-block-size is load-bearing here: a section with a content-driven height is exactly as tall as its children, so justify-content: center has nothing to distribute and the stack does not move, which reads as the property failing. The gap carries the distance between the three children so none of them needs a margin, and flex-direction: column is the line that decides what the other two properties will do, because justify-content always works along the main axis and align-items across it. In a row the same pair centres vertically and horizontally the other way around; in the .tag-cloud case, items wrap onto several lines and align-items only governs each line internally, so align-content is what centres the group of lines as a block.
align-items: center does one more thing that is easy to misread: on the cross axis it makes each item fit its own content instead of filling the container, which is why a paragraph centred inside a column often ends up as a narrow, ragged measure. Three ways out of that, in order of how often they are the right one: let the text block stretch with align-self: stretch and centre only its lines with text-align: center, cap it with max-inline-size in reading units and then centre the box, or keep the centring on the container and give the prose its own width. text-align: center in the first ruleset is doing that job for the heading and note, and it is inherited by the children rather than applied to them, which is another reason the wrapper never arrives.
The boundary that catches people is content taller than the space allotted to it. With min-block-size the container simply grows and the centring quietly stops mattering, which is the benign outcome and the reason to prefer it over height on any block whose text is translated or zoomed. The dangerous version is a scroll container that centres with justify-content: center or align-items: center: once the item is larger than the box, the alignment assigns negative free space, the item’s start edge lands before the scroll origin, and no amount of scrolling brings it back. The .dialog-body ruleset shows the portable fix — margin: auto on a single flex item centres it when there is room and pins nothing when there is not, because auto margins never take space away. The newer safe center keyword addresses the same flaw on the alignment properties themselves in current Chromium and Firefox, but it is a per-declaration opt-in, and auto margins behave the same on every engine that supports flexbox.
Expected output
One section element holds a centred stack of heading, note and button with no extra markup; the stack stays centred as the viewport narrows, and grows the section downward instead of overflowing when the viewport is short.
Usage notes
- State the size on the container rather than on the centred child; that single move is what removes the wrapper most guides reach for.
- Keep text-align: center on the container, because flex centring positions boxes and does nothing about the lines inside them.
Common mistakes
- Swapping flex-direction to column and leaving the two properties where they were, which centres the stack sideways instead of vertically.
- Writing height instead of min-block-size on a content-sized band, so translated text or enlarged type makes the section overlap whatever follows it.
- Reaching for absolute positioning with a translate to centre one item, then losing the space the element used to reserve for the rest of the page.
Caveats
- Centring only distributes space the container has left over, so an auto-height block on the main axis shows no movement at all and looks like a broken property.
- A centred flex item sizes to its content on the cross axis, so a paragraph in a centre-aligned column ends up as a narrow measure unless it is stretched or width-capped.
- The dvh units follow a mobile browser's shrinking and growing toolbars; svh is the safer floor when the band must fit the shortest viewport, and a plain rem floor when it must fit the reader's text size.
Alternatives
Flexbox centres without describing the frame, which is exactly what a single band needs: two properties on the container and the child keeps its own size. A grid reaches the same picture with one line, place-items: center, and is the better tool as soon as the layout has more than one thing to place, because a track list records the structure that a stack of alignment keywords does not. Choose flex for centring one area, grid when the page is really a set of columns.
Follow-up
Follow-up
Build a card grid that reflows without media queriesThe same axis reasoning scales up to a card grid that works out its own column count.
Related examples
Editorial links first, then deterministic same-task or same-topic candidates. Tags and shared language alone never qualify a candidate.
Alternative approach
Create a two-column layout with a fixed sidebarA grid track list reaches the same centred result once the layout has named columns to place.
Same task or topic
Build a card grid that reflows without media queriesSolves the Build a responsive layout task
Same task or topic
Keep a table header visible with sticky positioningSolves the Build a responsive layout task
References
- CSS Flexible Box Layout Module Level 1(opens in a new tab) — W3C. Normative definition of the main and cross axes each alignment property is resolved against.
- Basic concepts of flexbox - CSS(opens in a new tab) — MDN Web Docs. The axis vocabulary and the item sizing rules that decide what centring applies to.
- align-content CSS property(opens in a new tab) — MDN Web Docs. The property that positions wrapped flex lines, which align-items cannot reach.
Source page: https://devexamples.com/css/center-an-element-with-flexbox/