CSS Tutorial

CSS Project: Photo Gallery

A responsive image grid with captions. Gap, object-fit, and a hover lift keep the pictures in line.

What you will build

A six-photo wall for Harbor studio. Each cell is a figure: a cropped image and a caption. The grid holds a steady gap. On a wide window you get three columns. On a narrow one, two, then one. Hover lifts a frame without knocking the others out of line.

Use real images. The examples point at picsum.photos with stable seeds so the preview is not an empty box. Alt text still names what is in the shot.

Open an example with Try it in CSS. That loads /css/try — a live page preview.

Properties you will use

PropertyJob on this page
display: gridBuilds the photo wall
gapKeeps even space between frames
object-fit: coverFills a fixed-height crop without stretching
grid-template-columnsSets two or three columns with auto-fit
transform on :hoverLifts one figure without reflow

Figures, not bare images. A caption is part of the cell. If you float images with margin hacks, the gap will fight you.

Build in slices

First lock the crop. One figure, one image, one caption. Height is fixed. object-fit: coverdoes the cropping.

Example

<style>
  body { font-family: Georgia, serif; background: #e0f2fe; color: #0c4a6e; margin: 1.5rem; }
  figure {
    margin: 0;
    background: #fff;
    border-radius: 0.85rem;
    overflow: hidden;
    box-shadow: 0 10px 22px rgba(12, 74, 110, 0.12);
  }
  img {
    display: block;
    width: 100%;
    height: 11rem;
    object-fit: cover;
  }
  figcaption { padding: 0.7rem 0.85rem 0.85rem; font-size: 0.95rem; }
</style>
<figure>
  <img src="https://picsum.photos/seed/harbor-window/640/400" alt="Morning light on the studio window">
  <figcaption>Window table, 8:10</figcaption>
</figure>

Then wrap several figures in a grid. auto-fit and a minimum column width do the responsive work without a media query yet.

Example

<style>
  .gallery {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1rem;
  }
  figure { transition: transform 0.18s ease, box-shadow 0.18s ease; }
  figure:hover {
    transform: translateY(-6px);
    box-shadow: 0 16px 28px rgba(12, 74, 110, 0.18);
  }
</style>
<div class="gallery">
  <figure>
    <img src="https://picsum.photos/seed/harbor-loaf/640/400" alt="Sourdough cooling on a wooden board">
    <figcaption>Sourdough, still warm</figcaption>
  </figure>
  <figure>
    <img src="https://picsum.photos/seed/harbor-cup/640/400" alt="Espresso in a small cup">
    <figcaption>First espresso</figcaption>
  </figure>
</div>

Resize the preview at /css/try. Columns should drop before captions wrap into a cramped strip.

Complete page

Six frames from a Harbor studio morning. The page heading sits above the grid. Hover lift is transform only, so neighbors do not jump.

Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Harbor studio — morning wall</title>
  <style>
    * { box-sizing: border-box; }
    body {
      margin: 0;
      background: #e0f2fe;
      color: #0c4a6e;
      font-family: Georgia, "Times New Roman", serif;
    }
    header {
      padding: 1.6rem 1.25rem 0.4rem;
      max-width: 68rem;
      margin: 0 auto;
    }
    h1 { margin: 0 0 0.35rem; font-size: clamp(1.6rem, 3vw, 2.1rem); }
    .lead { margin: 0 0 1.2rem; color: #075985; }
    .gallery {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
      gap: 1rem;
      max-width: 68rem;
      margin: 0 auto;
      padding: 0 1.25rem 2rem;
    }
    figure {
      margin: 0;
      background: #fff;
      border-radius: 0.85rem;
      overflow: hidden;
      box-shadow: 0 10px 22px rgba(12, 74, 110, 0.12);
      transition: transform 0.18s ease, box-shadow 0.18s ease;
    }
    figure:hover {
      transform: translateY(-6px);
      box-shadow: 0 16px 28px rgba(12, 74, 110, 0.18);
    }
    img {
      display: block;
      width: 100%;
      height: 11rem;
      object-fit: cover;
    }
    figcaption {
      padding: 0.7rem 0.85rem 0.9rem;
      font-size: 0.95rem;
    }
  </style>
</head>
<body>
  <header>
    <h1>Harbor studio — morning wall</h1>
    <p class="lead">Six frames from the window side, shot before the cafe next door opened.</p>
  </header>
  <div class="gallery">
    <figure>
      <img src="https://picsum.photos/seed/harbor-window/640/400" width="640" height="400" alt="Morning light on the studio window">
      <figcaption>Window table, 8:10</figcaption>
    </figure>
    <figure>
      <img src="https://picsum.photos/seed/harbor-loaf/640/400" width="640" height="400" alt="Sourdough cooling on a wooden board">
      <figcaption>Sourdough, still warm</figcaption>
    </figure>
    <figure>
      <img src="https://picsum.photos/seed/harbor-cup/640/400" width="640" height="400" alt="Espresso in a small cup beside a saucer">
      <figcaption>First espresso</figcaption>
    </figure>
    <figure>
      <img src="https://picsum.photos/seed/harbor-press/640/400" width="640" height="400" alt="Prints hanging to dry on a studio line">
      <figcaption>Prints on the line</figcaption>
    </figure>
    <figure>
      <img src="https://picsum.photos/seed/harbor-pier/640/400" width="640" height="400" alt="Fishing boats along the pier">
      <figcaption>Pier from the door</figcaption>
    </figure>
    <figure>
      <img src="https://picsum.photos/seed/harbor-menu/640/400" width="640" height="400" alt="A handwritten cafe menu on cream paper">
      <figcaption>Today's board</figcaption>
    </figure>
  </div>
</body>
</html>

Practice tasks

  1. Raise the image height to 14rem and the gap to 1.25rem. Check that captions still sit under the crop.
  2. Change minmax(14rem, 1fr) to minmax(18rem, 1fr) so a tablet shows two columns sooner.
  3. Add a seventh figure with a new picsum seed. Preview the wrap at /css/try.

FAQ: CSS Project: Photo Gallery

Common questions about this page.

What is the StudyGrid CSS tutorial?

The StudyGrid CSS tutorial is a full beginner track: selectors, the box model, text, layout, flex, grid, and responsive design. Each chapter has copy-and-preview examples.

Should I run css gallery project examples locally for better learning?

Yes. Use the browser editor on StudyGrid for a quick check, then Download the example and run it on your computer. Local runs show real errors and the real toolchain, which is one of the fastest ways to learn css gallery project in this CSS CSS lesson (CSS Project: Photo Gallery).

Is the CSS editor the same as Try HTML?

No. Try CSS is a stylesheet preview at /css/try. Try HTML stays at /html/try. CSS lessons never open the HTML-only editor or the Python editor.

Do I need to install anything to learn CSS?

No. Open a chapter, click Try it in CSS, and the page preview updates in the browser.

Where should I start the CSS tutorial?

Start at CSS Intro, then Syntax, Selectors, and How To. After colors and the box model, continue to flex, grid, and media queries. Use Next at the bottom of each chapter.

Is the CSS tutorial free?

Yes. The CSS studio on StudyGrid (studygrid.in) is free: dashboard, chapters, and the live preview editor.