top of page

CSS Layout That Actually Makes Sense

  • ShiftQuality Contributor
  • Apr 3
  • 5 min read

The previous post in this path covered choosing a web stack. This post covers the skill that every web developer needs regardless of stack choice: CSS layout — specifically, the modern layout tools (Flexbox and Grid) that replaced the era of float hacks and clearfix divs.

CSS layout had a reputation for being unpredictable. That reputation was earned by a decade of abusing tools designed for document flow to achieve application layouts. Floats were designed for wrapping text around images, not for building navigation bars. Tables were designed for tabular data, not for page structure. Developers used them for layout anyway, because there was nothing better, and the results were fragile.

Flexbox and Grid changed this. They are actual layout tools, designed for laying out interfaces. They are predictable when you understand the mental model. The confusion that remains is not about the tools themselves — it is about when to use which one.

The Mental Model: One Dimension vs. Two

The decision between Flexbox and Grid comes down to dimensions.

Flexbox works in one dimension at a time — either a row or a column. It excels at distributing space among items along a single axis. A navigation bar with items spread across the width. A card with content stacked vertically. A group of buttons that should be evenly spaced. These are one-dimensional layout problems, and Flexbox handles them elegantly.

Grid works in two dimensions — rows and columns simultaneously. It excels at creating structured layouts where items need to be aligned in both directions. A dashboard with cards arranged in a grid. A page layout with a header, sidebar, content area, and footer. An image gallery where items align both horizontally and vertically. These are two-dimensional layout problems, and Grid handles them naturally.

The rule of thumb: if your layout is essentially a line of things (horizontal or vertical), use Flexbox. If your layout is a grid of things (rows and columns), use Grid. In practice, most interfaces use both — Grid for the overall page structure and Flexbox for the components within each grid area.

Flexbox: The Essentials

Flexbox operates on a container and its children. The container gets display: flex, and you control how children are arranged using properties on the container and the children.

Direction. flex-direction: row (default) lays out children horizontally. flex-direction: column lays them out vertically. This is the axis you are working with.

Justification. justify-content controls spacing along the main axis (the direction you set). space-between pushes items to the edges with equal space between them. center groups items in the middle. flex-start packs them to the beginning.

Alignment. align-items controls positioning along the cross axis (perpendicular to the direction). center vertically centers items in a row layout — the thing that was impossibly hard before Flexbox became a single property.

Growing and shrinking. flex-grow lets a child expand to fill available space. flex-shrink lets it compress when space is tight. flex-basis sets the initial size before growing or shrinking. The shorthand flex: 1 means "take up equal space with your siblings" — the most common use case.

Wrapping. flex-wrap: wrap allows items to flow to the next line when they do not fit. Without wrapping, Flexbox squeezes all items onto one line, which is often not what you want on small screens.

The pattern that solves 80% of Flexbox use cases: container with display: flex, gap for spacing between items, align-items: center for vertical centering, and flex-wrap: wrap for responsive behavior.

Grid: The Essentials

Grid operates on a container and its children, like Flexbox, but defines a two-dimensional structure.

Defining the grid. grid-template-columns defines the column structure. grid-template-columns: 1fr 2fr 1fr creates three columns where the middle column is twice the width of the side columns. fr is the fractional unit — it divides available space proportionally.

Responsive columns without media queries. grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)) creates as many columns as will fit, with each column at least 300px wide. On a wide screen, you get four columns. On a narrow screen, you get one. This single line replaces dozens of lines of media queries.

Placing items. Grid items are placed automatically by default — filling cells left to right, top to bottom. For explicit placement, grid-column: 1 / 3 makes an item span from column 1 to column 3. grid-row: 2 / 4 makes it span rows 2 through 4.

Gap. gap sets spacing between grid cells, just like Flexbox. This is cleaner than adding margins to items, because the gap only appears between items — not on the edges.

Named areas. For page-level layouts, grid-template-areas lets you name regions and assign items to them visually. This makes complex layouts readable — you can see the layout structure in the CSS itself.

Responsive Design Without the Pain

Responsive design means your layout works on all screen sizes — phones, tablets, desktops, and everything in between. The old approach was writing media queries that changed the layout at specific breakpoints. The modern approach lets Flexbox and Grid handle most responsive behavior automatically.

Flexbox wrapping is intrinsically responsive. A row of cards with flex-wrap: wrap and flex: 1 1 300px (each card at least 300px, growing to fill space) rearranges from four columns to two columns to one column as the screen narrows. No media queries required.

Grid auto-fit is intrinsically responsive. repeat(auto-fit, minmax(250px, 1fr)) adjusts the number of columns to the available width. The items flow naturally without breakpoints.

Media queries still have a role — but for structural changes, not for spacing tweaks. When the sidebar should move below the content on mobile, a media query changes the Grid template. When the navigation should collapse to a hamburger menu, a media query changes the Flexbox direction. These are structural layout shifts that require explicit decisions about how the interface reorganizes.

The principle: let the layout tools handle fluid sizing and wrapping. Use media queries only when the layout structure fundamentally changes between screen sizes.

Common Layout Patterns

Centered content with max-width. The most common page layout: content centered horizontally with a maximum width so it does not stretch across ultra-wide screens. max-width: 1200px; margin: 0 auto; — this is not Flexbox or Grid, and it is still the right tool for this job.

Holy grail layout. Header, footer, sidebar, and content area. Grid handles this with named areas: define the areas in grid-template-areas, assign each section to its area, and add a media query to stack them vertically on mobile.

Card grid. A responsive grid of equally sized cards. display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem; — three lines and it works on every screen size.

Navigation bar. Logo on the left, links on the right. display: flex; justify-content: space-between; align-items: center; — Flexbox's core use case.

Form layout. Labels and inputs aligned in a grid. display: grid; grid-template-columns: auto 1fr; gap: 0.75rem 1rem; — labels take their natural width, inputs fill the remaining space.

The Takeaway

CSS layout is no longer the adversarial experience it once was. Flexbox handles one-dimensional layouts — rows and columns of items that need spacing, alignment, and wrapping. Grid handles two-dimensional layouts — structured arrangements where items need to align in both directions. Together they cover the vast majority of layout needs with predictable, readable CSS.

The mental model is simple: one dimension, use Flexbox. Two dimensions, use Grid. Most interfaces use both. And the responsive behavior is largely built in — wrapping and auto-fit handle screen size changes without media queries for most situations.

Next in the "Modern Web Architecture" learning path: We'll cover state management in web applications — how to structure the data your frontend needs to display and update without creating a tangled mess.

Comments


bottom of page