Responsive photo gallery
Galleries are a classic use of CSS Grid: one line of CSS can decide how many columns fit. The starter uses coloured tiles as stand-ins for photos, so it works anywhere. Swap in your own pictures whenever you like.
Skills you'll practise
- Semantic HTML
- CSS Grid
- Responsive design
- aspect-ratio
Steps
Step 1: Mark up the photos
Each photo is a
<figure>with the picture and a<figcaption>. Add at least six.Show a hintHide the hint
Using a real image? Write
<img src="..." alt="what the picture shows">in place of the coloured<div>.Step 2: Make a grid
Turn the gallery into a grid with a gap between the tiles.
Show a hintHide the hint
display: grid; gap: 16px;on the.galleryelement.Step 3: Let the columns decide themselves
Use
repeat(auto-fill, minmax(180px, 1fr))so the grid fits as many columns as it can, with no media queries.Step 4: Keep every tile the same shape
Give each photo
aspect-ratio: 4 / 3so tiles stay even however wide they get.Show a hintHide the hint
For real images, add
object-fit: coverso they fill the tile without stretching.Step 5: Add a gentle hover
Lift a tile slightly on hover, and turn the effect off for people who prefer reduced motion.
Show a hintHide the hint
Wrap the transition in
@media (prefers-reduced-motion: no-preference) { ... }.
Starter code
It already shows something on the page. The TODO comments mark where to start.
<main>
<h1>My gallery</h1>
<section class="gallery">
<figure>
<div class="photo sunrise"></div>
<figcaption>Sunrise</figcaption>
</figure>
<figure>
<div class="photo forest"></div>
<figcaption>Forest</figcaption>
</figure>
<!-- TODO: add at least four more figures -->
</section>
</main>
body {
font-family: system-ui, sans-serif;
background: #fcf4e8;
color: #15120c;
}
.gallery {
/* TODO: make this a responsive grid */
}
.photo {
height: 120px;
}
.sunrise { background: linear-gradient(135deg, #ffd59e, #f28c6b); }
.forest { background: linear-gradient(135deg, #a8d5a2, #3e7f5c); }
Example solution
One way to finish it. Have a go first; yours doesn't need to match.
Reveal the solutionHide the solution
<main>
<h1>My gallery</h1>
<section class="gallery" aria-label="Photos">
<figure>
<div class="photo sunrise" role="img" aria-label="Orange sunrise"></div>
<figcaption>Sunrise</figcaption>
</figure>
<figure>
<div class="photo forest" role="img" aria-label="Green forest"></div>
<figcaption>Forest</figcaption>
</figure>
<figure>
<div class="photo ocean" role="img" aria-label="Blue ocean"></div>
<figcaption>Ocean</figcaption>
</figure>
<figure>
<div class="photo meadow" role="img" aria-label="Pale green meadow"></div>
<figcaption>Meadow</figcaption>
</figure>
<figure>
<div class="photo dusk" role="img" aria-label="Purple dusk sky"></div>
<figcaption>Dusk</figcaption>
</figure>
<figure>
<div class="photo desert" role="img" aria-label="Sandy desert"></div>
<figcaption>Desert</figcaption>
</figure>
</section>
</main>
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: system-ui, sans-serif;
background: #fcf4e8;
color: #15120c;
}
main {
max-width: 960px;
margin: 0 auto;
padding: 32px 16px;
}
h1 {
margin: 0 0 20px;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 16px;
}
figure {
margin: 0;
overflow: hidden;
background: #ffffff;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(46, 38, 24, 0.08);
}
.photo {
width: 100%;
aspect-ratio: 4 / 3;
}
figcaption {
padding: 10px 12px;
font-size: 14px;
color: #4f483d;
}
.sunrise { background: linear-gradient(135deg, #ffd59e, #f28c6b); }
.forest { background: linear-gradient(135deg, #a8d5a2, #3e7f5c); }
.ocean { background: linear-gradient(135deg, #a7d8f0, #2f6f9f); }
.meadow { background: linear-gradient(135deg, #e6f4d7, #9cc98a); }
.dusk { background: linear-gradient(135deg, #c9b6e4, #5b4b8a); }
.desert { background: linear-gradient(135deg, #f5e0b7, #c9935a); }
@media (prefers-reduced-motion: no-preference) {
figure {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
figure:hover {
transform: translateY(-3px);
box-shadow: 0 10px 20px rgba(46, 38, 24, 0.12);
}
}
Stretch goal
Make one photo stand out by letting it span two columns with grid-column: span 2, and check the layout still works on a phone-sized screen.