CSS Grid for Responsive Simulation Cards

One line of CSS replaces eighteen lines of media queries. grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)) is the pattern behind every card grid on this site.

The Single Line That Does Everything

The simulation index pages list dozens of cards. On a wide monitor they should appear in 4 or 5 columns; on a phone, 1 or 2. The classic approach requires three or four @media breakpoints. The CSS Grid approach needs exactly this:

.sim-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1rem;
}

That's it. No breakpoints. No JavaScript. Resize the browser and the grid reflows automatically.

Live Demo (drag the corner to resize)

💧 SPH Fluid
☄️ N-Bodies
🌌 Galaxy
🐜 Ants
🌀 Lorenz
🧬 Life
🌊 Ocean
🏔️ Terrain

↔ Drag the right edge of the demo box to see the grid reflow.

How It Works

repeat(auto-fill, …) tells the browser: "create as many columns as fit." minmax(260px, 1fr) means: "each column is at least 260px wide, but grows equally to fill remaining space."

So at 800px wide with a 1rem gap, you fit 2 × 260px + gap = ~532px → 3 columns almost fit → 2 columns each growing to ~395px. The math works out automatically.

auto-fill vs auto-fit

There are two keywords — they only differ when items don't fill a full row:

Use auto-fill when you have a known minimum card width and don't want cards to stretch too wide. Use auto-fit when you want cards to always fill the full container.

Adding a max-width cap

/* Prevent very wide cards on large screens */
.sim-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr));
  gap: 1rem;
  max-width: 1400px;
  margin-inline: auto;
}

/* Or clamp the card width directly: */
.sim-card {
  max-width: 380px;
}

The Card Itself

The card pattern used here: hover border glow, aspect-ratio thumbnail, scale transform, and padding that fits the text without overflow:

.sim-card {
  background: var(--color-surface-2);
  border: 1px solid var(--color-border);
  border-radius: 14px;
  overflow: hidden;
  text-decoration: none;
  color: var(--color-text);
  transition: border-color 0.15s ease, transform 0.15s ease;
}

.sim-card:hover {
  border-color: var(--color-accent);
  transform: translateY(-2px);
}

.sim-card-thumb {
  aspect-ratio: 16 / 9;
  background: var(--color-surface);
  overflow: hidden;
}

.sim-card-thumb img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

.sim-card-body {
  padding: 0.9rem 1rem;
}

.sim-card-title {
  font-size: var(--text-sm);
  font-weight: 700;
  margin-bottom: 0.25rem;
}

A11y note: Make the entire card a link (<a> wrapping all content), not a button. Screen readers announce it as a link and keyboard users can tab to it naturally. Avoid pointer-events: none on inner elements — it breaks text selection.