Skip to main content
CodeOath
← All posts

HTML & CSS82 min total · 18 parts

CSS Fundamentals: The Box Model, Specificity, Positioning, and Layout

Part 13 of 18 · ~2 min

Grid In Depth

The category page's top level isn't one-dimensional — a filter sidebar on the left, the product grid on the right, both needing to be defined together:

.category-page {
  display: grid;
  grid-template-columns: 240px 1fr; /* sidebar holds its width; content takes the rest */
  gap: 24px;
}

fr only exists inside Grid, and what it means is: give this track a proportional slice of whatever room remains once every fixed-size track has already taken its cut. Set one track to a hard 240px and a neighboring 1fr track claims the entirety of what's left over, automatically, every time the container is resized.

The product grid itself needs to respond to however many cards actually fit, without a single media query:

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 24px;
}

However many 220px-minimum columns can physically fit the available width, that's how many get created, and any room left over is divided evenly across them — resize the container and the column count recalculates itself on its own, nothing else to write. auto-fit and its close cousin auto-fill differ in exactly one situation worth knowing: with auto-fit, an empty track collapses to zero width and its space is handed to the tracks that do have content, so four cards in a row that could fit five stretch to fill the row. auto-fill instead leaves that fifth track's space sitting empty, reserved, in case a fifth card shows up later. For a product grid where the card count is whatever's in stock, auto-fit is almost always the one you want; auto-fill earns its keep when the empty slots themselves are meaningful, like a form laid out in a fixed number of columns.

Grid also has a job inside the card itself, for the compact "list view" toggle some shoppers prefer over the grid — image, title, price, and button arranged in a row instead of stacked, and named grid areas make the arrangement genuinely readable straight off the CSS:

.card--list {
  display: grid;
  grid-template-columns: 96px 1fr auto;
  grid-template-areas: "image title button" "image price button";
}
.card--list img          { grid-area: image; }
.card--list h3            { grid-area: title; }
.card--list .price        { grid-area: price; }
.card--list .card__add    { grid-area: button; }

Read that grid-template-areas block like a floor plan rather than a CSS declaration — each quoted line is one row of the grid, laid out left to right exactly as it will render, and repeating image on both lines tells Grid to stretch that one area tall enough to sit beside both the title and the price, with no row-span number to work out by hand.