WEB DEVELOPMENT · CSS TUTORIAL

Create a Responsive Card Grid with CSS Grid

Make article or project cards adapt to their container without fixed widths, clipped text or JavaScript layout calculations.

Three browser panels show cards arranged in three columns, two columns and one column as available width narrows.
Conceptual illustration accompanying this article.

A card grid is a familiar way to present articles, projects or products. It becomes harder to maintain when every card receives a fixed width or when several competing media queries try to repair the layout. CSS Grid can express the underlying rule more directly: place as many useful columns as the available space can support.

This tutorial builds a small article collection using ordinary HTML and CSS. It does not depend on Bootstrap or a JavaScript layout library. You can open the standalone card-grid demo, resize the window and inspect how the same source order works at different widths. The demonstration also includes deliberately uneven text lengths.

Choose the content structure before the columns

A list is a sensible starting point for a collection of related articles. Each list item contains an article element with a heading, description and link. The grid belongs on the list, while the card styling belongs on the article inside it. Keeping those responsibilities separate makes the markup easier to extend.

Use headings that fit the surrounding page. In the standalone demo, each card has an H2 below the page’s H1. On a homepage where a section already has an H2, the card heading would normally be an H3. Copy the layout pattern without assuming that its heading level is appropriate everywhere.

<ul class="tutorial-grid">
  <li>
    <article class="tutorial-card">
      <img src="/images/articles/responsive-card-grid-600.jpg"
           width="600" height="400" alt="" loading="lazy">
      <h2>Build a responsive card grid</h2>
      <p>A practical guide to fitting cards into the available space.</p>
      <p class="card-action"><a href="/web-development/responsive-card-grid/">
        Read the responsive card-grid guide</a></p>
    </article>
  </li>
  <!-- Add more list items with the same article structure. -->
</ul>

The image has an empty alternative because, in this particular card, the heading and description already convey the information needed to choose the link. An informative product image might need meaningful alternative text instead. Make that decision from the image’s role rather than copying the empty value into every card.

Let the container decide how many columns fit

The grid rule below asks for automatically fitted columns with a preferred minimum of sixteen rem and a flexible maximum of one fraction. The inner minimum caps that lower bound at the container’s available width. That prevents a card’s preferred minimum from forcing an avoidable horizontal overflow in a narrower container.

.tutorial-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.tutorial-grid > li { min-width: 0; }
.tutorial-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 1.25rem;
  border: 1px solid #ded8bd;
  border-radius: 6px;
  background: #fff;
  overflow-wrap: anywhere;
}
.tutorial-card img { display: block; width: 100%; height: auto; }
.tutorial-card h2 { font-size: 1.3rem; line-height: 1.3; }
.tutorial-card .card-action { margin-top: auto; padding-top: 1rem; }
.tutorial-card a { color: #514300; }
.tutorial-card a:focus-visible { outline: 3px solid #926500; outline-offset: 4px; }

There is no special phone width in that calculation. A narrow sidebar can produce one column even on a wide screen, while a spacious main area can produce several. This is useful when the same component appears in different page templates. The minimum card width is still a design choice: choose it based on the actual content, not a device label.

Understand auto-fit and the available tracks

With this pattern, auto-fit allows empty repeated tracks to collapse, letting existing cards use the space. Auto-fill can retain those empty tracks instead. The difference becomes visible when there are only one or two cards in a wide container, so test that case rather than looking only at a fully populated example.

If the design always needs exactly three columns at a particular width, explicit tracks and media queries may be the clearer choice. A fluid rule is not automatically superior to a deliberate breakpoint. The aim is to express the intended layout with the least fragile set of rules.

Keep the card’s internal layout independent

The card uses a column flex layout so its final action can sit near the bottom of a stretched grid item. A description can grow naturally above it. This avoids assigning a fixed height to the paragraph, which can clip text when a title wraps differently or the visitor increases the font size.

Cards in one grid row can share the row’s height without implying that every row will be identical. Content still determines how much height is needed. If your design requires all rows to match, examine whether that requirement helps readers or merely creates large empty spaces. Avoid hiding useful descriptions to satisfy a decorative alignment goal.

Reserve image space and use appropriate files

The sample image declares its actual width and height. CSS then scales the image to the card while retaining the aspect ratio. Providing dimensions helps the browser reserve space before the image finishes loading. A consistent source ratio also avoids needing to crop unrelated images into a shape they were not composed for.

Use a smaller file for a thumbnail than for a full-width article illustration. This site’s illustrated cards use dedicated six-hundred-pixel variants alongside larger article versions. Responsive source selection can refine that choice further, but begin by avoiding an unnecessarily large image in every small card. Keep an eye on the combined cost of a whole grid, not only one attractive file.

Preserve reading and keyboard order

The source order should already make sense without the grid. Do not use dense packing or visual reordering simply to fill small gaps when that would make keyboard focus jump unpredictably across the page. A visitor following links in sequence should encounter the same progression that a reader expects from the visible content.

The example uses one descriptive link per card rather than several identical destinations. A whole-card anchor can also be appropriate, but it cannot contain another interactive control such as a bookmark button. Decide where the interactive boundary belongs before adding click handlers to the surrounding article.

Test content that challenges the layout

Try a very long title, a long unbroken identifier, a missing image and a single-card collection. The minimum-width reset and wrapping rule help prevent one awkward piece of text from expanding a grid track. They are not a substitute for reviewing the actual labels and descriptions.

Also zoom in, navigate with a keyboard and reduce the available width until only one column remains. A grid that looks fine in a desktop screenshot can still require sideways scrolling after text enlargement. Keep the card’s information readable and its focus indicator visible rather than treating the narrow layout as a compressed version of the desktop artwork.

Reuse the pattern with local names

Keep component class names scoped so the experiment does not accidentally change every article element or image across your site. The demo uses tutorial-specific names; adapt them to your own naming convention when integrating the pattern. Shared components should reduce repetition without introducing broad selectors whose effects are difficult to trace.

For the underlying CSS behavior, see MDN’s references for repeat(), minmax() and grid auto-placement. Continue with reliable asset URLs when moving this component between directory-based pages.