[go: up one dir, main page]

Entry 01

Content grid with breakouts

Use it as the container of every page, whether or not anything on it goes wider than the content. A centered max-width wrapper is the sign, such as .container, .wrapper or Tailwind's mx-auto max-w-*. One grid on the section replaces the section > .container wrapper pair and costs no more than it, and any child can be content width, wider, or edge to edge. Put it on main for a page of flowing content, or on each section. A band, a figure or a block that an editor later wants wider then takes one class, with no negative margin and no new wrapper.

Open
Make the frame narrower. The breakout shrinks to content width, the gutters hold, and nothing overflows.
Code CSS · 2 blocks · 20 lines

The container defines three nested widths with named grid lines:

.content-grid {
  --gutter: 1.5rem;
  --content: 64rem;
  --breakout: 80rem;

  display: grid;
  grid-template-columns:
    [full-width-start] minmax(var(--gutter), 1fr)
    [breakout-start] minmax(0, calc((var(--breakout) - var(--content)) / 2))
    [content-start] min(100% - var(--gutter) * 2, var(--content)) [content-end]
    minmax(0, calc((var(--breakout) - var(--content)) / 2)) [breakout-end]
    minmax(var(--gutter), 1fr) [full-width-end];
}

Each child picks a width with grid-column. Content is the default:

:is(.content-grid, .full-width) > * { grid-column: content; }
:is(.content-grid, .full-width) > .breakout { grid-column: breakout; }
:is(.content-grid, .full-width) > .full-width {
  grid-column: full-width;
  display: grid;
  grid-template-columns: inherit;
}
Why it works, the rules and the credits 4 reasons · 4 rules · credits

Why it works

  1. Two lines named content-start and content-end create a named area, content. That is why grid-column: content works with no line numbers.
  2. min(100% - 2 × gutter, max) shrinks the content column on small screens with no media query.
  3. minmax(0, …) lets the breakout tracks collapse, so a breakout falls back to content width when there is no room. With a fixed breakout size the page overflows on small screens.
  4. grid-template-columns: inherit gives a full-width band the same grid, so content inside it lines up with the page column without another wrapper. This is Kevin Powell's addition. In Ryan Mulligan's original the full-width child is a plain box.

Rules

  1. Every child must be placed. An unplaced child of the grid lands in the gutter track.
  2. Every direct child is a grid item. Wrap a run of inline elements in one element.
  3. Change a width by overriding --content, not by writing a new column template.
  4. In a pass over existing CSS, replace each centered max-width wrapper with the grid, and keep the wrapper's width as --content on its section.

In other systems

The column template goes wherever the project defines reusable styles. Where child selectors are not available, as in StyleX or Tailwind without a custom variant, each child sets its own grid-column to content, breakout or full-width.

Credits

Borrowed from: Kevin Powell, A new approach to container and wrapper classes, 2023-11-09 · Ryan Mulligan, Layout Breakouts with CSS Grid · Stephanie Eckles, SmolCSS breakout grid

Docs: MDN: named grid lines · MDN: min()

Entry 02

Intrinsic grid

Use it for any set of equal cards or tiles. It replaces a column count per breakpoint.

Open
Change the width. The number of columns follows the frame, and at 360 there is one column and no overflow.
Code CSS · 5 lines
.grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}
Why it works, the rules and the credits 2 reasons · 1 rule · support · credits

Why it works

  1. auto-fit creates as many 16rem columns as the row holds, and 1fr shares what is left. The column count follows the container.
  2. min(100%, 16rem) lets the minimum shrink to the container. Without it a 200px container overflows.

Rules

  1. auto-fit stretches a short row to fill the width. Use auto-fill when the item count changes, such as a filtered list, so cards keep their size.

Support

Chrome
79
Firefox
76
Safari
11.1

Credits

Borrowed from: Kevin Powell, Breakpoint-Free CSS Grid Layouts, 2025-02-19 · Stephanie Eckles, Smol Responsive CSS Grid · Una Kravets, Ten modern layouts in one line of CSS

Entry 03

Subgrid rows shared across cards

Use it when cards in a row have parts that should line up, such as title, body and footer, whatever the length of their content.

Open
Titles, bodies and footers line up across a row, whatever their length. Change the width to reflow the rows.
Code CSS · 12 lines
.cards {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}

.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  row-gap: 0.5rem;
}
Why it works, the rules and the credits 1 reason · 2 rules · support · credits

Why it works

  1. Each card spans three rows of the parent grid and adopts those tracks. The tallest title in a row sets the title height for every card in that row.

Rules

  1. The span must equal the number of parts in the card. Without grid-row: span N every part piles into one row.
  2. Set row-gap on the card, or it inherits the parent's gap between its parts.

Support

Chrome
117
Firefox
71
Safari
16

Credits

Borrowed from: Josh W. Comeau, Brand New Layouts with CSS Subgrid, 2025-11-25 · Kevin Powell, Subgrid & Container Queries change how we can create layouts, 2023-10-26

Entry 04

Sidebar that wraps on its own

Use it for any pair where one side has an ideal width and the other takes the rest, such as a media object, an input with a button, or a page with an aside.

Open
Make the frame narrower. When the main side would get less than half the width, it wraps below and both sides fill the row.
Code CSS · 16 lines
.with-sidebar {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.sidebar {
  flex-basis: 20rem;
  flex-grow: 1;
}

.main {
  flex-basis: 0;
  flex-grow: 999;
  min-inline-size: 50%;
}
Why it works, the rules and the credits 2 reasons · 4 rules · support · credits

Why it works

  1. The main side's huge flex-grow takes all the free space, which holds the sidebar at its basis.
  2. Once the main side would get less than half the container it wraps below, and both sides grow to full width.

Rules

  1. The wrap point is a share of the container, not a length. Change min-inline-size to move it.
  2. Drop the sidebar's flex-basis for a sidebar sized by its content.
  3. For a sticky sidebar, add align-self: start beside position: sticky and its inset. The two sides stretch to the same height, and a stretched sidebar has no room to stick.
  4. A bare img or video as one of the sides stretches to the height of the row and distorts. Set align-items: start on the container.

Support

Chrome
84
Firefox
63
Safari
14.1

Credits

Borrowed from: Heydon Pickering and Andy Bell, The Sidebar, Every Layout

Entry 05

Container queries with container units

Use it for any component that appears in slots of different widths. The component responds to the space it is given, where a media query only knows the viewport.

Open
The wide slot lays the card out in two columns with a larger heading. Make the frame narrower until that slot is under 30rem: it becomes the narrow card.
Code CSS · 10 lines
.slot { container-type: inline-size; }

.card h2 { font-size: clamp(1.25rem, 1rem + 2cqi, 2rem); }

@container (width > 30rem) {
  .card {
    display: grid;
    grid-template-columns: 12rem 1fr;
  }
}
Why it works, the rules and the credits 2 reasons · 6 rules · support · credits

Why it works

  1. The query measures the nearest container, so the same card is right in a sidebar and in a wide column.
  2. 1cqi is 1% of that container's inline size. The clamp() math from Fluid sizes with clamp() carries over, per component.

Rules

  1. The container must be an ancestor. An element cannot query itself.
  2. A container cannot take its width from its content. Never put container-type on a shrink-to-fit element, or it collapses to zero.
  3. With no container ancestor the query never matches. Kevin Powell makes header, main and footer containers in his reset, so most components need none of their own.
  4. A container cannot also be a subgrid. Subgrid rows shared across cards and this entry need separate elements.
  5. Container units are different from queries. With no container above the element, cqi measures the viewport, so one token written with cqi serves the page and every slot.
  6. Never register a fluid token that uses cqi with @property. A registered length computes once on :root, where there is no container, and every slot then gets the viewport's value.

Support

Chrome
105
Firefox
110
Safari
16

Credits

Borrowed from: Kevin Powell, Improve your reset with these modern CSS additions, 2024-09-04 · Una Kravets, Container queries land in stable browsers, 2023-02-14 · Josh W. Comeau, A Friendly Introduction to Container Queries, 2024-11-04 · Stephanie Eckles, Container Query Units and Fluid Typography

Entry 06

Stack layers with grid

Use it whenever things sit on top of each other, such as text over an image, a badge on a card, or two icons that swap. It replaces position: absolute with its offsets, sizes and transforms.

Open
Change the width. Each stack keeps the size of its largest layer and the badge stays in its corner.
Code CSS · 5 lines
.stack { display: grid; }
.stack > * { grid-area: 1 / 1; }

.stack > .title { place-self: center; }
.stack > .badge { place-self: start end; }
Why it works, the rules and the credits 3 reasons · 2 rules · credits

Why it works

  1. Every child goes into the same grid cell, so they overlap.
  2. The layers stay in flow. The container takes the size of its largest layer, where an absolutely positioned child adds nothing to it.
  3. place-self aligns one layer inside the cell. Without it the layer stretches to fill.

Rules

  1. A layer later in the DOM paints on top. Use z-index only to change that order.
  2. Keep position: absolute for a layer that must not affect the container's size.

Credits

Borrowed from: Ana Tudor, @anatudor on X, 2025-03-29

Docs: MDN: grid-area · MDN: place-self

Entry 07

Safe alignment

Use it wherever content is centered or end-aligned in a container that can become too small, such as a tab row, a toolbar or a vertically centered modal.

Open
At full width the tabs are centred. At 360 the row scrolls, and you can still reach the first tab.
Code CSS · 5 lines
.tabs {
  display: flex;
  overflow-x: auto;
  justify-content: safe center;
}
Why it works, the rules and the credits 1 reason · 2 rules · support · credits

Why it works

  1. Plain center pushes overflow off the start edge, where scrolling cannot reach it. safe falls back to start once the content overflows.

Rules

  1. It works on every align-*, justify-* and place-* property.
  2. Auto margins on the item center it the same way and are safe in every browser that has flexbox. Push one item away with an auto margin has them.

Support

Chrome
115
Firefox
63
Safari
17.6

Credits

Borrowed from: Temani Afif, Safe align your content, 2025-06-10

Entry 08

overflow: clip over hidden

Use it whenever you want to cut off overflow and do not need scrolling.

Open
The frame has no horizontal scrollbar. Scroll down: the label stays stuck to the top.
Code CSS · 1 line
.hero { overflow-x: clip; }
Why it works, the rules and the credits 2 reasons · 3 rules · support · credits

Why it works

  1. hidden turns the element into a scroll container and sets the other axis to auto. That causes stray scrollbars and breaks position: sticky inside it.
  2. clip cuts the overflow and does neither.

Rules

  1. Put it on the element that overflows, not on html or body.
  2. Keep hidden or auto for elements a script scrolls. clip blocks that too.
  3. Keep hidden or auto on an element with resize. With clip the browser draws no resize handle.

Support

Chrome
90
Firefox
81
Safari
16

Credits

Borrowed from: Kevin Powell, 2 better alternatives to overflow: hidden, 2023-12-14