CSS 14 views

Responsive CSS Framework for Image Cards

Create responsive image cards with CSS grid layout and hover effects, perfect for galleries.

By TWC Team • Feb 20, 2026

Code

/* Responsive Image Card Grid (Gallery) — production-ready CSS.
   Drop in: wrap cards in .c-card-grid; each card uses .c-card + .c-card__media + .c-card__content. */

:root {
  --card-min: 250px;
  --gap: 16px;
  --radius: 12px;
  --shadow: 0 10px 24px rgba(0, 0, 0, 0.12);
  --overlay: rgba(0, 0, 0, 0.55);
  --text: #fff;
  --ease: cubic-bezier(.2, .8, .2, 1);
  --dur: 220ms;
}

.c-card-grid {
  /* Fallback for older browsers: flex grid */
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
}

/* Prefer CSS Grid when supported for better packing/consistency */
@supports (display: grid) {
  .c-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--card-min), 1fr));
    gap: var(--gap);
  }
}

.c-card {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  background: #111; /* Prevents flash while image loads */
  box-shadow: var(--shadow);
  /* GPU-friendly: transform/opacity only for hover */
  transition: transform var(--dur) var(--ease);
  will-change: transform; /* Performance hint for hover-heavy galleries */
}

/* Flex fallback: approximate grid columns without expensive selectors */
.c-card-grid > .c-card {
  flex: 1 1 var(--card-min);
  min-width: var(--card-min);
}

.c-card:focus-within,
.c-card:hover {
  transform: translateY(-2px) scale(1.03);
}

.c-card__media {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3; /* Keeps layout stable; prevents CLS */
  object-fit: cover;
}

/* Fallback for browsers without aspect-ratio support */
@supports not (aspect-ratio: 1) {
  .c-card__media {
    height: 220px;
  }
}

.c-card__content {
  position: absolute;
  inset: auto 0 0 0;
  padding: 12px 14px;
  color: var(--text);
  background: linear-gradient(to top, var(--overlay), rgba(0, 0, 0, 0));
  opacity: 0;
  transform: translateY(6px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}

.c-card:focus-within .c-card__content,
.c-card:hover .c-card__content {
  opacity: 1;
  transform: translateY(0);
}

/* Accessibility: respect reduced motion preferences */
@media (prefers-reduced-motion: reduce) {
  .c-card,
  .c-card__content {
    transition: none;
  }
}

/* Small screens: slightly smaller minimum card width for denser galleries */
@media (max-width: 480px) {
  :root { --card-min: 200px; }
}

/* Example usage:
   <div class="c-card-grid">
     <article class="c-card">
       <img class="c-card__media" src="image.jpg" alt="Project preview">
       <div class="c-card__content">Project Title</div>
     </article>
   </div>
*/
Back to Snippets