Website Markup Using CSS Flexbox
Flexbox is a one-dimensional layout system for aligning elements in a row or column. It's the primary tool for component-level work: navigation, cards, buttons, forms, toolbars. Knowing 8–10 key properties solves 80% of alignment tasks.
Main Axis and Cross Axis
The key concept of Flexbox is the main axis and the cross axis:
.container {
display: flex;
flex-direction: row; /* Horizontal (default) */
/* or: column */ /* Vertical */
/* or: row-reverse */ /* Horizontal, right to left */
}
justify-content aligns along the main axis, align-items — along the cross axis. The confusion happens here — remember that justify = main = the direction of flex-direction.
Navigation
.nav {
display: flex;
align-items: center; /* Center vertically */
gap: 8px;
padding: 0 24px;
height: 64px;
}
.nav__logo {
margin-inline-end: auto; /* Pushes everything else to the right */
}
.nav__links {
display: flex;
gap: 4px;
list-style: none;
margin: 0;
padding: 0;
}
.nav__cta {
margin-inline-start: 16px; /* Small gap from links */
}
margin-inline-end: auto on one element — the classic Flexbox trick for separating groups. Logo on the left, everything else on the right — without absolute positioning.
Centering
The most common task — the infamous "center vertically":
/* Center in parent */
.hero {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* Or shorter */
.hero {
display: flex;
place-content: center; /* Both properties at once */
min-height: 100vh;
}
/* Center one element inside flex container */
.card__icon {
align-self: center;
}
Cards with Equal Height
.cards {
display: flex;
gap: 24px;
flex-wrap: wrap; /* Wrap to new line */
}
.card {
flex: 1 1 280px; /* grow: 1, shrink: 1, basis: 280px */
display: flex;
flex-direction: column;
}
/* Button always at the bottom of card, regardless of text length */
.card__body {
flex: 1; /* Take all available space */
}
.card__action {
margin-top: auto; /* Or: align-self: flex-end on parent column */
}
flex: 1 1 280px — shorthand for three properties: flex-grow: 1 (stretches), flex-shrink: 1 (shrinks), flex-basis: 280px (minimum width). Cards fill the row but don't become narrower than 280px.
Forms
.form-group {
display: flex;
flex-direction: column;
gap: 6px;
}
/* Field with button in one line */
.input-group {
display: flex;
}
.input-group__field {
flex: 1;
border-right: none;
border-radius: 6px 0 0 6px;
}
.input-group__btn {
border-radius: 0 6px 6px 0;
white-space: nowrap;
}
/* Row of fields */
.form-row {
display: flex;
gap: 16px;
}
.form-row .form-group { flex: 1; }
/* Name takes more space than zip code */
.form-row .form-group--name { flex: 3; }
.form-row .form-group--zip { flex: 1; }
Icon + Text (Common Pattern)
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 10px 20px;
border-radius: 6px;
font-weight: 500;
cursor: pointer;
border: none;
background: var(--color-accent);
color: white;
transition: background 150ms ease;
}
.btn__icon {
width: 16px;
height: 16px;
flex-shrink: 0; /* Icon doesn't shrink with long text */
}
inline-flex — the button behaves like inline-block but has a flex context inside for aligning icon and text.
Sidebar Layout
.sidebar-layout {
display: flex;
align-items: flex-start; /* Sidebar doesn't stretch to full height */
gap: 32px;
}
.sidebar-layout__sidebar {
flex: 0 0 280px; /* Fixed width, doesn't stretch */
position: sticky;
top: 80px; /* Stick on scroll */
}
.sidebar-layout__main {
flex: 1; /* Takes remaining space */
min-width: 0; /* Solves overflow problem in flex context */
}
min-width: 0 — critical for the main column. By default, a flex-item cannot be narrower than its content (min-width: auto). This causes horizontal scrolling with long words, tables, code blocks. min-width: 0 allows shrinking.
flex-wrap and Line Alignment
.tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-content: flex-start; /* Lines stick to top, not stretched */
}
/* Tag takes exactly as much space as needed */
.tag {
flex: 0 1 auto;
padding: 4px 12px;
border-radius: 100px;
background: var(--color-surface);
border: 1px solid var(--color-border);
white-space: nowrap;
}
Beginner Mistakes
display: flex on <img>. The image becomes a flex container, breaking its behavior. Wrapping in <figure> or <div> is the better solution.
Forgetting flex-shrink: 0 on icons. When space is tight, flex shrinks the icon before the text, deforming it.
justify-content: space-between for three or more elements. The last row with flex-wrap will spread out — outer elements stretch to edges. Solution:
/* Bad with wrap */
.cards { justify-content: space-between; }
/* Good */
.cards {
display: flex;
flex-wrap: wrap;
gap: 24px;
}
.card { flex: 1 1 280px; max-width: calc(33.333% - 16px); }
height: 100% doesn't work in flex. Child elements stretch by default if align-items isn't flex-start. For explicit filling: align-self: stretch (default) or flex: 1 on the vertical axis.
Timeframe
| Task | Time |
|---|---|
| Navigation (header with flex layout) | 0.5 day |
| Page with cards and sidebar | 1 day |
| Full Landing page (Flexbox-based) | 1.5–2 days |







