Last 30 Days
No notifications
Modern CSS provides two powerful layout systems: Flexbox for one-dimensional layouts and CSS Grid for two-dimensional layouts. Combined with positioning and stacking contexts, you can build any design.
| Property | Values | Purpose | ||||
display | flex | Activates flex container | ||||
flex-direction | row, column | Main axis direction | ||||
justify-content | center, space-between, β¦ | Alignment on main axis | ||||
align-items | center, stretch, β¦ | Alignment on cross axis | ||||
flex-wrap | wrap, nowrap | Allow wrapping | ||||
gap | 1rem | Space between items | CSS Grid (Two-Dimensional) | Property | Values | Purpose |
display | grid | Activates grid container | ||||
grid-template-columns | 1fr 1fr 1fr | Define columns | ||||
grid-template-rows | auto 1fr auto | Define rows | ||||
gap | 1rem | Spacing between cells | ||||
grid-column | 1 / 3 | Span columns (child) | ||||
place-items | center | Align cell content |
static β Normal flow (default)
relative β Offset from normal position
absolute β Positioned relative to nearest positioned ancestor
fixed β Positioned relative to viewport
sticky β Scrolls normally then sticks at thresholdz-index only works on positioned elements (relative, absolute, fixed, sticky). A new stacking context is created by elements with z-index, opacity < 1, transform, or filter. Children cannot escape their parent's stacking context.
For years, web layout was a hack-fest of float, clearfix, and tables-pretending-to-be-layouts. Modern CSS gives you two purpose-built tools that solve 95% of layouts:
Every element has a display value that controls how it flows:
Set display: flex on a *parent* and its direct children become flex items. By default they sit in a row, side by side.
.row {
display: flex;
gap: 16px; /* space between children */
align-items: center; /* vertical alignment */
justify-content: space-between; /* horizontal distribution */
}On the parent:
| Property | Common values | Does what | |||
flex-direction | row / column | Lay items horizontally or vertically | |||
justify-content | flex-start / center / space-between / space-around | Distribution along the main axis | |||
align-items | stretch / center / flex-start / flex-end | Alignment on the cross axis | |||
gap | any length | Space between items (replaces margin tricks) | |||
flex-wrap | nowrap / wrap | Allow items to drop to a new line | On the child: | Property | Does what |
flex: 1 | Grow to fill remaining space | ||||
flex: 0 0 200px | Don't grow, don't shrink, basis 200 px | ||||
align-self: center | Override parent's align-items for one item | ||||
margin-left: auto | Push this item to the far right (handy in nav bars) |
.parent {
display: flex;
justify-content: center; /* horizontal */
align-items: center; /* vertical */
min-height: 100vh;
}Grid lets you draw a table of cells and place items into them.
.layout {
display: grid;
grid-template-columns: 1fr 3fr; /* sidebar + main */
grid-template-rows: auto 1fr auto; /* header, body, footer */
gap: 16px;
min-height: 100vh;
}fr Unitfr is a *fraction of remaining space*. After fixed widths and gaps are subtracted, every fr shares what's left.
grid-template-columns: 200px 1fr 1fr;
/* 200px sidebar, then two equal fluid columns */.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1rem;
}Translation: "fit as many β₯220px columns as you can; share leftover space equally; no media queries needed". This single line gives you a responsive card grid.
Name your areas, then assign children to them:
.layout {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }| Use Flexbox when⦠| Use Grid when⦠| |||
| Items flow in one direction | You need rows *and* columns | |||
| Item sizes are content-driven | The container defines the structure | |||
| You're building a navbar, toolbar, button row | You're building a page layout, dashboard, card grid | |||
| You want items to wrap naturally | You want explicit cell placement | You can β and should β nest them: a Grid page layout containing Flex navbars and card rows. Positioning β When Things Need to Float Above the Page
| Value | Behaviour |
static | Default. Normal flow. | |||
relative | Stays in flow but you can nudge with top/left. Establishes a containing block. | |||
absolute | Removed from flow. Positioned relative to the nearest positioned ancestor. | |||
fixed | Removed from flow. Positioned relative to the viewport (sticks while scrolling). | |||
sticky | Acts relative until you scroll past a threshold, then fixed. | A common pattern: a parent with Intermediate: Stacking Context & | absolute | fixed |
z-index other than auto
opacity less than 1transform, filter, perspective, clip-pathisolation: isolate (a great way to deliberately fence off a section)1. Background & borders of the context element
2. Children with negative z-index
3. Non-positioned flow content
4. Positioned children (ascending z-index)
If two siblings live in different contexts, their z-index numbers don't compete with each other.
In flexbox, an auto margin absorbs all extra space:
.nav { display: flex; gap: 16px; }
.nav .logout { margin-left: auto; } /* push to far right */Cleaner than justify-content: space-between when you only need one item separated.
Lets a nested grid inherit the row/column tracks of its parent β perfect for aligning items inside cards to a global grid.
.card { display: grid; grid-template-rows: subgrid; }Until recently you could only respond to *viewport* size. Container queries let a component respond to *its own* size:
.card { container-type: inline-size; }@container (min-width: 400px) {
.card .image { float: left; }
}
Now the same card component lays itself out differently in a sidebar vs the main area, no JavaScript needed.
Maintain a 16:9 ratio without padding tricks:
.video { aspect-ratio: 16 / 9; width: 100%; }min-content, max-content, and fit-content() size things to their *content*:
.tag { width: max-content; } /* exactly as wide as the text */
.btn { width: fit-content(200px); } /* up to 200px, smaller if content is shorter */1. Build a navbar (logo on left, links centred, login on far right) with flexbox + an auto margin.
2. Build a 3-column responsive blog grid using grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)).
3. Recreate a "Holy Grail" page layout (header, sidebar, content, aside, footer) with named grid areas.
4. Use position: sticky to keep a sidebar's TOC visible while the page scrolls.