One-line CSS layouts: ten patterns worth knowing

Modern CSS has made it possible to build robust, responsive layouts with remarkably little code. The ten patterns below each rely on a single powerful declaration, and understanding them can save you significant time and effort compared to older techniques that often required multiple properties and media queries.

Fundamentals: Grid and centering

Centering content is a classic CSS challenge, and place-items: center solves it cleanly. Applied to a grid container, it is a shorthand for setting both align-items and justify-items to center, placing the child content perfectly in the middle of the parent regardless of its intrinsic size.

.parent {
  display: grid;
  place-items: center;
}

Flexible rows and columns

For marketing-style rows of three items that stack on mobile without media queries, use the flex shorthand. Its syntax is flex: <flex-grow> <flex-shrink> <flex-basis>. Setting it to flex: 0 1 150px lets items start at a 150px base size, shrink when space is tight, but never grow to fill extra space. Change the grow value to 1 and the items will also stretch to fill available space as they wrap.

.parent {
  display: flex;
}

.child {
  flex: 0 1 150px;
}
.parent {
  display: flex;
}

.child {
  flex: 1 1 150px;
}

For a classic sidebar layout, grid-template-columns: minmax(150px, 25%) 1fr is a single-line solution. The sidebar's width is minmax and will occupy 25% of the parent until that value drops below 150px, at which point it locks to the minimum. The main content area fills the rest with a single 1fr track.

.parent {
  display: grid;
  grid-template-columns: minmax(150px, 25%) 1fr;
}

Often used as a global app or website layout, a "pancake stack" has a header, main content, and footer. On a grid container, the declaration grid-template-rows: auto 1fr auto makes the header and footer take the size of their content and the main area take up all the remaining space, naturally keeping the footer at the bottom even when content is short.

.parent {
  display: grid;
  grid-template-rows: auto 1fr auto;
}

Extend that idea to the classic Holy Grail layout, which adds left and right sidebars. A single-line grid-template: auto 1fr auto / auto 1fr auto property defines both rows and columns (before and after the slash, respectively). The sidebars, like the header and footer, size automatically to their children, but in the horizontal direction.

.parent {
  display: grid;
  grid-template: auto 1fr auto / auto 1fr auto;
}

Spans and responsive repetition

The 12-column grid remains a staple. With grid-template-columns: repeat(12, 1fr), you get 12 equal tracks and can place items with explicit grid lines or the span keyword. For example, grid-column: 1 / 13 is equivalent to grid-column: 1 / span 12, and both make an item span the full width.

.parent {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
}

.child-span-12 {
  grid-column: 1 / 13;
}

Combining repeat, auto-fit, and minmax()—the RAM pattern—creates a fully responsive layout. The declaration grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)) auto-places children that each have a minimum width of 150px and grow to fill the available space as the viewport widens. With auto-fit, items stretch to fill the whole row; switching to auto-fill keeps them at their base size beyond the 150px threshold, leaving empty tracks instead.

.parent {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.parent {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

Smart justification and sizing

For card-style content with a title on top and an image on the bottom, Flexbox combined with justify-content: space-between handles the spacing. Set the container to display: flex and use flex-direction: column, and the space-between value anchors the first and last items to the container's edges, keeping the descriptive text elegantly distributed in the middle.

.parent {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

Responsive, legible sizing gets a boost from the clamp() function. For example, width: clamp(23ch, 50%, 46ch) allows an element to maintain a 50% width until it exceeds 46 character units on wide viewports or drops below 23 character units on narrow ones. This works well for text containers, preventing lines from getting too long. The same technique can be used on typography, such as font-size: clamp(1.5rem, 20vw, 3rem), which keeps a headline legible relative to the viewport while never exceeding its minimum or maximum sizes.

.parent {
  width: clamp(23ch, 60%, 46ch);
}

True aspect ratios

Maintaining an element's proportions, like a 16:9 video frame, now has a native property. Instead of the older padding-top hack with hardcoded percentages (such as padding: 56.25%), the aspect-ratio: 16 / 9 declaration keeps the element's proportional shape as it resizes. You can express any ratio, such as 1 / 1 for a square or 2 / 1 for a wide format, and it works cleanly with images, videos, and embedded iframes.

.video {
  aspect-ratio: 16 / 9;
}