Open demo

CSS code

HTML
<div><span class="lbl">Captions on hover and keyboard focus</span>
<section class="gg" aria-labelledby="gg-title">
  <div class="gh"><div><p class="gh-kicker">Northlight Studio</p><h2 id="gg-title">Iceland, 2025</h2></div><p class="gh-meta">6 photographs · Hekla Sigurðardóttir</p></div>
  <ul class="gg-grid" role="list">
    <li><a class="gg-item" href="https://images.unsplash.com/photo-1504829857797-ddff29c27927?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1504829857797-ddff29c27927?auto=format&fit=crop&w=720&h=540&q=70" width="720" height="540" loading="lazy" alt="Jagged dark peaks behind a black sand beach and shallow tidal pools at sunrise"><span class="gg-cap"><strong>Black sand at first light</strong><span>East coast · 08:42</span></span></a></li>
    <li><a class="gg-item" href="https://images.unsplash.com/photo-1476610182048-b716b8518aae?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1476610182048-b716b8518aae?auto=format&fit=crop&w=720&h=540&q=70" width="720" height="540" loading="lazy" alt="A tall waterfall pouring off a green cliff into a pool, with a river winding across the plain at sunset"><span class="gg-cap"><strong>The falls at sunset</strong><span>South coast · 22:10</span></span></a></li>
    <li><a class="gg-item" href="https://images.unsplash.com/photo-1531168556467-80aace0d0144?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1531168556467-80aace0d0144?auto=format&fit=crop&w=720&h=540&q=70" width="720" height="540" loading="lazy" alt="A river running along the bottom of a deep, moss-covered canyon"><span class="gg-cap"><strong>Moss canyon</strong><span>South coast · 14:05</span></span></a></li>
    <li><a class="gg-item" href="https://images.unsplash.com/photo-1491466424936-e304919aada7?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1491466424936-e304919aada7?auto=format&fit=crop&w=720&h=540&q=70" width="720" height="540" loading="lazy" alt="A person with a headlamp standing at the mouth of a blue ice cave under a starry sky"><span class="gg-cap"><strong>Inside the glacier</strong><span>Southeast · 02:15</span></span></a></li>
    <li><a class="gg-item" href="https://images.unsplash.com/photo-1529963183134-61a90db47eaf?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1529963183134-61a90db47eaf?auto=format&fit=crop&w=720&h=540&q=70" width="720" height="540" loading="lazy" alt="Green aurora over a lagoon scattered with floating blocks of ice"><span class="gg-cap"><strong>Aurora over the ice lagoon</strong><span>Southeast · 23:40</span></span></a></li>
    <li><a class="gg-item" href="https://images.unsplash.com/photo-1474690870753-1b92efa1f2d8?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1474690870753-1b92efa1f2d8?auto=format&fit=crop&w=720&h=540&q=70" width="720" height="540" loading="lazy" alt="A tall stepped concrete church tower under a blue sky, with people crossing the square in front"><span class="gg-cap"><strong>Hallgrímskirkja</strong><span>Reykjavík · 11:20</span></span></a></li>
  </ul>
</section></div>

<div><span class="lbl">Square tiles with captions underneath</span>
<section class="sq" aria-labelledby="sq-title">
  <div class="gh"><div><p class="gh-kicker">Still Water</p><h2 id="sq-title">Alpine lakes</h2></div><p class="gh-meta">8 photographs · Mara Lind</p></div>
  <ul class="sq-grid" role="list">
    <li><figure><img src="https://images.unsplash.com/photo-1501785888041-af3ef285b470?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="A rowing boat on a turquoise lake below steep rocky mountains"><figcaption><span class="sq-title">Morning row</span><span class="sq-when">June 14, 07:10</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1470770841072-f978cf4d019e?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="A wooden boathouse on stilts in a green lake beneath cloud-wrapped peaks"><figcaption><span class="sq-title">The boathouse</span><span class="sq-when">June 14, 09:30</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="The bow of a wooden boat on green water, facing grey limestone mountains"><figcaption><span class="sq-title">From the bow</span><span class="sq-when">June 15, 08:05</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1493246507139-91e8fad9978e?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="A turquoise lake reflecting jagged peaks lit pink at sunrise"><figcaption><span class="sq-title">Pink peaks</span><span class="sq-when">July 2, 05:48</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1473448912268-2022ce9509d8?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="Tall pines along a still green river, with mountains fading into mist"><figcaption><span class="sq-title">River in the pines</span><span class="sq-when">July 3, 10:15</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="A wooden jetty stretching into a calm blue lake lined with forest"><figcaption><span class="sq-title">The jetty</span><span class="sq-when">July 4, 12:30</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1494500764479-0c8f2919a3d8?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="A lone tree standing in a still lake under a purple dusk sky"><figcaption><span class="sq-title">The lone tree</span><span class="sq-when">August 9, 20:55</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="A pine forest and a wide glacial valley below snowy mountains"><figcaption><span class="sq-title">Valley lookout</span><span class="sq-when">August 10, 16:40</span></figcaption></figure></li>
  </ul>
</section></div>

<div><span class="lbl">Featured photo grid</span>
<section class="fg" aria-labelledby="fg-title">
  <div class="gh"><div><p class="gh-kicker">Vertical City</p><h2 id="fg-title">Looking up</h2></div><p class="gh-meta">5 photographs · Lena Ortiz</p></div>
  <ul class="fg-grid" role="list">
    <li><a class="fg-item" href="https://images.unsplash.com/photo-1511818966892-d7d671e672a2?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1511818966892-d7d671e672a2?auto=format&fit=crop&w=960&h=960&q=70" width="960" height="960" loading="lazy" alt="Looking straight up between glass skyscrapers under a heavy grey sky, in black and white"><span class="fg-tag">Glass canyon<small>Plate 01</small></span></a></li>
    <li><a class="fg-item" href="https://images.unsplash.com/photo-1431576901776-e539bd916ba2?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1431576901776-e539bd916ba2?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="Two glass towers seen from below, their windows glowing orange against a white sky"><span class="fg-tag">Amber</span></a></li>
    <li><a class="fg-item" href="https://images.unsplash.com/photo-1449824913935-59a10b8d2000?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1449824913935-59a10b8d2000?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="A wide avenue lined with tall buildings, with yellow taxis waiting at the lights"><span class="fg-tag">Avenue</span></a></li>
    <li><a class="fg-item" href="https://images.unsplash.com/photo-1519501025264-65ba15a82390?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1519501025264-65ba15a82390?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="A wet street at dusk between dark towers, with car lights reflected on the road"><span class="fg-tag">Rain hour</span></a></li>
    <li><a class="fg-item" href="https://images.unsplash.com/photo-1514565131-fce0801e5785?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1514565131-fce0801e5785?auto=format&fit=crop&w=480&h=480&q=70" width="480" height="480" loading="lazy" alt="A downtown skyline with one tall spire across the water at dusk, the moon above it"><span class="fg-tag">Across the river</span></a></li>
  </ul>
</section></div>
CSS
/* Grid galleries. Shared header */
.gh{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:6px 24px;margin-bottom:20px}
.gh-kicker{font-size:.75rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:#a2461f}
.gh h2{margin-top:4px;font-size:1.75rem;line-height:1.15;letter-spacing:-.02em}
.gh-meta{font-size:.9rem;color:#625c53}

/* 1. Captions on hover and focus: each tile is a link to the full-size photo */
.gg{--gg-gap:16px;--gg-radius:12px;--gg-ratio:4/3;--gg-focus:#a2461f}
.gg-grid{list-style:none;display:grid;grid-template-columns:1fr;gap:var(--gg-gap)}
@media (min-width:576px){.gg-grid{grid-template-columns:repeat(2,1fr)}}
@media (min-width:992px){.gg-grid{grid-template-columns:repeat(3,1fr)}}
.gg-item{position:relative;display:block;aspect-ratio:var(--gg-ratio);border-radius:var(--gg-radius);overflow:hidden;background:#d9d4cc;color:#fff;text-decoration:none}
.gg-item img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .6s cubic-bezier(.2,.7,.2,1)}
.gg-cap{position:absolute;left:0;right:0;bottom:0;display:flex;flex-direction:column;gap:2px;padding:48px 16px 14px;
  background:linear-gradient(to top,rgba(14,12,10,.88),rgba(14,12,10,0));opacity:0;transform:translateY(10px);transition:opacity .3s,transform .3s}
.gg-cap strong{font-size:1rem;font-weight:600}
.gg-cap span{font-size:.8rem;color:#ece7df}
.gg-item:hover img,.gg-item:focus-visible img{transform:scale(1.05)}
.gg-item:hover .gg-cap,.gg-item:focus-visible .gg-cap{opacity:1;transform:none}
.gg-item:focus-visible{outline:3px solid var(--gg-focus);outline-offset:3px}
@media (hover:none){.gg-cap{opacity:1;transform:none}}

/* 2. Square tiles with captions underneath */
.sq-grid{list-style:none;display:grid;grid-template-columns:repeat(2,1fr);gap:24px 16px}
@media (min-width:768px){.sq-grid{grid-template-columns:repeat(4,1fr)}}
.sq-grid img{width:100%;height:auto;aspect-ratio:1;object-fit:cover;display:block;border-radius:10px;background:#d9d4cc}
.sq-grid figcaption{margin-top:10px}
.sq-title{display:block;font-size:.95rem;font-weight:600}
.sq-when{display:block;margin-top:2px;font-size:.8rem;color:#625c53}

/* 3. Featured photo grid: the first photo spans two columns and two rows */
.fg-grid{list-style:none;display:grid;grid-template-columns:repeat(2,1fr);gap:16px}
@media (min-width:768px){.fg-grid{grid-template-columns:repeat(4,1fr)}}
.fg-grid li:first-child{grid-column:span 2;grid-row:span 2}
.fg-item{position:relative;display:block;aspect-ratio:1;border-radius:14px;overflow:hidden;background:#d9d4cc;color:#1d1b18;text-decoration:none}
.fg-item img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .6s cubic-bezier(.2,.7,.2,1)}
.fg-item:hover img,.fg-item:focus-visible img{transform:scale(1.05)}
.fg-tag{position:absolute;left:12px;bottom:12px;padding:6px 12px;border-radius:999px;background:rgba(255,255,255,.94);font-size:.8rem;font-weight:600}
.fg-tag small{margin-left:8px;font-size:.75rem;font-weight:500;color:#625c53}
.fg-grid li:first-child .fg-tag{left:16px;bottom:16px;padding:8px 16px;font-size:.95rem}
.fg-item:focus-visible{outline:3px solid #a2461f;outline-offset:3px}
@media (prefers-reduced-motion:reduce){.gg-item img,.gg-cap,.fg-item img{transition:none}
  .gg-item:hover img,.gg-item:focus-visible img,.fg-item:hover img,.fg-item:focus-visible img{transform:none}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Captions on hover and keyboard focus</span>
<section class="gg" aria-labelledby="gg-title">
  <div class="gh d-flex flex-wrap align-items-end justify-content-between"><div><p class="gh-kicker">Northlight Studio</p><h2 id="gg-title" class="gh-title">Iceland, 2025</h2></div><p class="gh-meta">6 photographs · Hekla Sigurðardóttir</p></div>
  <div class="row row-cols-1 row-cols-sm-2 row-cols-lg-3 g-3">
    <div class="col"><a class="gg-item d-block position-relative" href="https://images.unsplash.com/photo-1504829857797-ddff29c27927?auto=format&fit=crop&w=2000&q=70"><span class="ratio d-block ratio-4x3"><img src="https://images.unsplash.com/photo-1504829857797-ddff29c27927?auto=format&fit=crop&w=720&h=540&q=70" class="object-fit-cover" width="720" height="540" loading="lazy" alt="Jagged dark peaks behind a black sand beach and shallow tidal pools at sunrise"></span><span class="gg-cap"><strong>Black sand at first light</strong><span>East coast · 08:42</span></span></a></div>
    <div class="col"><a class="gg-item d-block position-relative" href="https://images.unsplash.com/photo-1476610182048-b716b8518aae?auto=format&fit=crop&w=2000&q=70"><span class="ratio d-block ratio-4x3"><img src="https://images.unsplash.com/photo-1476610182048-b716b8518aae?auto=format&fit=crop&w=720&h=540&q=70" class="object-fit-cover" width="720" height="540" loading="lazy" alt="A tall waterfall pouring off a green cliff into a pool, with a river winding across the plain at sunset"></span><span class="gg-cap"><strong>The falls at sunset</strong><span>South coast · 22:10</span></span></a></div>
    <div class="col"><a class="gg-item d-block position-relative" href="https://images.unsplash.com/photo-1531168556467-80aace0d0144?auto=format&fit=crop&w=2000&q=70"><span class="ratio d-block ratio-4x3"><img src="https://images.unsplash.com/photo-1531168556467-80aace0d0144?auto=format&fit=crop&w=720&h=540&q=70" class="object-fit-cover" width="720" height="540" loading="lazy" alt="A river running along the bottom of a deep, moss-covered canyon"></span><span class="gg-cap"><strong>Moss canyon</strong><span>South coast · 14:05</span></span></a></div>
    <div class="col"><a class="gg-item d-block position-relative" href="https://images.unsplash.com/photo-1491466424936-e304919aada7?auto=format&fit=crop&w=2000&q=70"><span class="ratio d-block ratio-4x3"><img src="https://images.unsplash.com/photo-1491466424936-e304919aada7?auto=format&fit=crop&w=720&h=540&q=70" class="object-fit-cover" width="720" height="540" loading="lazy" alt="A person with a headlamp standing at the mouth of a blue ice cave under a starry sky"></span><span class="gg-cap"><strong>Inside the glacier</strong><span>Southeast · 02:15</span></span></a></div>
    <div class="col"><a class="gg-item d-block position-relative" href="https://images.unsplash.com/photo-1529963183134-61a90db47eaf?auto=format&fit=crop&w=2000&q=70"><span class="ratio d-block ratio-4x3"><img src="https://images.unsplash.com/photo-1529963183134-61a90db47eaf?auto=format&fit=crop&w=720&h=540&q=70" class="object-fit-cover" width="720" height="540" loading="lazy" alt="Green aurora over a lagoon scattered with floating blocks of ice"></span><span class="gg-cap"><strong>Aurora over the ice lagoon</strong><span>Southeast · 23:40</span></span></a></div>
    <div class="col"><a class="gg-item d-block position-relative" href="https://images.unsplash.com/photo-1474690870753-1b92efa1f2d8?auto=format&fit=crop&w=2000&q=70"><span class="ratio d-block ratio-4x3"><img src="https://images.unsplash.com/photo-1474690870753-1b92efa1f2d8?auto=format&fit=crop&w=720&h=540&q=70" class="object-fit-cover" width="720" height="540" loading="lazy" alt="A tall stepped concrete church tower under a blue sky, with people crossing the square in front"></span><span class="gg-cap"><strong>Hallgrímskirkja</strong><span>Reykjavík · 11:20</span></span></a></div>
  </div>
</section></div>

<div><span class="lbl">Square tiles with captions underneath</span>
<section class="sq" aria-labelledby="sq-title">
  <div class="gh d-flex flex-wrap align-items-end justify-content-between"><div><p class="gh-kicker">Still Water</p><h2 id="sq-title" class="gh-title">Alpine lakes</h2></div><p class="gh-meta">8 photographs · Mara Lind</p></div>
  <div class="row row-cols-2 row-cols-md-4 gx-3 gy-4">
    <div class="col"><figure class="figure m-0 d-block"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1501785888041-af3ef285b470?auto=format&fit=crop&w=480&h=480&q=70" class="figure-img object-fit-cover" width="480" height="480" loading="lazy" alt="A rowing boat on a turquoise lake below steep rocky mountains"></span><figcaption class="figure-caption"><span class="sq-title">Morning row</span><span class="sq-when">June 14, 07:10</span></figcaption></figure></div>
    <div class="col"><figure class="figure m-0 d-block"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1470770841072-f978cf4d019e?auto=format&fit=crop&w=480&h=480&q=70" class="figure-img object-fit-cover" width="480" height="480" loading="lazy" alt="A wooden boathouse on stilts in a green lake beneath cloud-wrapped peaks"></span><figcaption class="figure-caption"><span class="sq-title">The boathouse</span><span class="sq-when">June 14, 09:30</span></figcaption></figure></div>
    <div class="col"><figure class="figure m-0 d-block"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&w=480&h=480&q=70" class="figure-img object-fit-cover" width="480" height="480" loading="lazy" alt="The bow of a wooden boat on green water, facing grey limestone mountains"></span><figcaption class="figure-caption"><span class="sq-title">From the bow</span><span class="sq-when">June 15, 08:05</span></figcaption></figure></div>
    <div class="col"><figure class="figure m-0 d-block"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1493246507139-91e8fad9978e?auto=format&fit=crop&w=480&h=480&q=70" class="figure-img object-fit-cover" width="480" height="480" loading="lazy" alt="A turquoise lake reflecting jagged peaks lit pink at sunrise"></span><figcaption class="figure-caption"><span class="sq-title">Pink peaks</span><span class="sq-when">July 2, 05:48</span></figcaption></figure></div>
    <div class="col"><figure class="figure m-0 d-block"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1473448912268-2022ce9509d8?auto=format&fit=crop&w=480&h=480&q=70" class="figure-img object-fit-cover" width="480" height="480" loading="lazy" alt="Tall pines along a still green river, with mountains fading into mist"></span><figcaption class="figure-caption"><span class="sq-title">River in the pines</span><span class="sq-when">July 3, 10:15</span></figcaption></figure></div>
    <div class="col"><figure class="figure m-0 d-block"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?auto=format&fit=crop&w=480&h=480&q=70" class="figure-img object-fit-cover" width="480" height="480" loading="lazy" alt="A wooden jetty stretching into a calm blue lake lined with forest"></span><figcaption class="figure-caption"><span class="sq-title">The jetty</span><span class="sq-when">July 4, 12:30</span></figcaption></figure></div>
    <div class="col"><figure class="figure m-0 d-block"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1494500764479-0c8f2919a3d8?auto=format&fit=crop&w=480&h=480&q=70" class="figure-img object-fit-cover" width="480" height="480" loading="lazy" alt="A lone tree standing in a still lake under a purple dusk sky"></span><figcaption class="figure-caption"><span class="sq-title">The lone tree</span><span class="sq-when">August 9, 20:55</span></figcaption></figure></div>
    <div class="col"><figure class="figure m-0 d-block"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?auto=format&fit=crop&w=480&h=480&q=70" class="figure-img object-fit-cover" width="480" height="480" loading="lazy" alt="A pine forest and a wide glacial valley below snowy mountains"></span><figcaption class="figure-caption"><span class="sq-title">Valley lookout</span><span class="sq-when">August 10, 16:40</span></figcaption></figure></div>
  </div>
</section></div>

<div><span class="lbl">Featured photo grid</span>
<section class="fg" aria-labelledby="fg-title">
  <div class="gh d-flex flex-wrap align-items-end justify-content-between"><div><p class="gh-kicker">Vertical City</p><h2 id="fg-title" class="gh-title">Looking up</h2></div><p class="gh-meta">5 photographs · Lena Ortiz</p></div>
  <div class="row g-3">
    <div class="col-md-6"><a class="fg-item fg-feature d-block position-relative" href="https://images.unsplash.com/photo-1511818966892-d7d671e672a2?auto=format&fit=crop&w=2000&q=70"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1511818966892-d7d671e672a2?auto=format&fit=crop&w=960&h=960&q=70" class="object-fit-cover" width="960" height="960" loading="lazy" alt="Looking straight up between glass skyscrapers under a heavy grey sky, in black and white"></span><span class="fg-tag">Glass canyon<small>Plate 01</small></span></a></div>
    <div class="col-md-6"><div class="row row-cols-2 g-3">
      <div class="col"><a class="fg-item d-block position-relative" href="https://images.unsplash.com/photo-1431576901776-e539bd916ba2?auto=format&fit=crop&w=2000&q=70"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1431576901776-e539bd916ba2?auto=format&fit=crop&w=480&h=480&q=70" class="object-fit-cover" width="480" height="480" loading="lazy" alt="Two glass towers seen from below, their windows glowing orange against a white sky"></span><span class="fg-tag">Amber</span></a></div>
      <div class="col"><a class="fg-item d-block position-relative" href="https://images.unsplash.com/photo-1449824913935-59a10b8d2000?auto=format&fit=crop&w=2000&q=70"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1449824913935-59a10b8d2000?auto=format&fit=crop&w=480&h=480&q=70" class="object-fit-cover" width="480" height="480" loading="lazy" alt="A wide avenue lined with tall buildings, with yellow taxis waiting at the lights"></span><span class="fg-tag">Avenue</span></a></div>
      <div class="col"><a class="fg-item d-block position-relative" href="https://images.unsplash.com/photo-1519501025264-65ba15a82390?auto=format&fit=crop&w=2000&q=70"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1519501025264-65ba15a82390?auto=format&fit=crop&w=480&h=480&q=70" class="object-fit-cover" width="480" height="480" loading="lazy" alt="A wet street at dusk between dark towers, with car lights reflected on the road"></span><span class="fg-tag">Rain hour</span></a></div>
      <div class="col"><a class="fg-item d-block position-relative" href="https://images.unsplash.com/photo-1514565131-fce0801e5785?auto=format&fit=crop&w=2000&q=70"><span class="ratio d-block ratio-1x1"><img src="https://images.unsplash.com/photo-1514565131-fce0801e5785?auto=format&fit=crop&w=480&h=480&q=70" class="object-fit-cover" width="480" height="480" loading="lazy" alt="A downtown skyline with one tall spire across the water at dusk, the moon above it"></span><span class="fg-tag">Across the river</span></a></div>
    </div></div>
  </div>
</section></div>
CSS
/* Grid galleries on Bootstrap's grid (.row-cols-*) and .ratio. Shared header */
.gh{gap:6px 24px;margin-bottom:20px}
.gh-kicker{margin:0;font-size:.75rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:#a2461f}
.gh-title{margin:4px 0 0;font-size:1.75rem;font-weight:700;line-height:1.15;letter-spacing:-.02em}
.gh-meta{margin:0;font-size:.9rem;color:#625c53}

/* 1. Captions on hover and focus */
.gg{--gg-radius:12px;--gg-focus:#a2461f}
.gg-item{border-radius:var(--gg-radius);overflow:hidden;background:#d9d4cc;color:#fff;text-decoration:none}
.gg-item img{transition:transform .6s cubic-bezier(.2,.7,.2,1)}
.gg-cap{position:absolute;left:0;right:0;bottom:0;display:flex;flex-direction:column;gap:2px;padding:48px 16px 14px;
  background:linear-gradient(to top,rgba(14,12,10,.88),rgba(14,12,10,0));opacity:0;transform:translateY(10px);transition:opacity .3s,transform .3s}
.gg-cap strong{font-size:1rem;font-weight:600}
.gg-cap span{font-size:.8rem;color:#ece7df}
.gg-item:hover img,.gg-item:focus-visible img{transform:scale(1.05)}
.gg-item:hover .gg-cap,.gg-item:focus-visible .gg-cap{opacity:1;transform:none}
.gg-item:focus-visible{outline:3px solid var(--gg-focus);outline-offset:3px}
@media (hover:none){.gg-cap{opacity:1;transform:none}}

/* 2. Square tiles with captions underneath */
.sq .figure-img{margin:0;border-radius:10px;background:#d9d4cc}
.sq .figure-caption{margin-top:10px;color:#1d1b18}
.sq-title{display:block;font-size:.95rem;font-weight:600}
.sq-when{display:block;margin-top:2px;font-size:.8rem;color:#625c53}

/* 3. Featured photo grid: a .col-md-6 square beside a 2 × 2 nested row */
.fg-item{border-radius:14px;overflow:hidden;background:#d9d4cc;color:#1d1b18;text-decoration:none}
.fg-item img{transition:transform .6s cubic-bezier(.2,.7,.2,1)}
.fg-item:hover img,.fg-item:focus-visible img{transform:scale(1.05)}
.fg-tag{position:absolute;left:12px;bottom:12px;padding:6px 12px;border-radius:999px;background:rgba(255,255,255,.94);font-size:.8rem;font-weight:600}
.fg-tag small{margin-left:8px;font-size:.75rem;font-weight:500;color:#625c53}
.fg-feature .fg-tag{left:16px;bottom:16px;padding:8px 16px;font-size:.95rem}
.fg-item:focus-visible{outline:3px solid #a2461f;outline-offset:3px}
@media (prefers-reduced-motion:reduce){.gg-item img,.gg-cap,.fg-item img{transition:none}
  .gg-item:hover img,.gg-item:focus-visible img,.fg-item:hover img,.fg-item:focus-visible img{transform:none}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#625c53] uppercase">Captions on hover and keyboard focus</span>
<section aria-labelledby="gg-title">
  <div class="mb-5 flex flex-wrap items-end justify-between gap-x-6 gap-y-1.5"><div><p class="text-xs leading-[normal] font-bold tracking-[.14em] text-[#a2461f] uppercase">Northlight Studio</p><h2 id="gg-title" class="mt-1 text-[1.75rem] leading-[1.15] font-bold tracking-[-.02em]">Iceland, 2025</h2></div><p class="text-[.9rem] leading-[normal] text-[#625c53]">6 photographs · Hekla Sigurðardóttir</p></div>
  <ul class="grid grid-cols-1 gap-4 min-[576px]:grid-cols-2 min-[992px]:grid-cols-3" role="list">
    <li><a class="group relative block aspect-[4/3] overflow-hidden rounded-xl bg-[#d9d4cc] text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#a2461f]" href="https://images.unsplash.com/photo-1504829857797-ddff29c27927?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1504829857797-ddff29c27927?auto=format&fit=crop&w=720&h=540&q=70" class="block size-full object-cover transition-transform duration-[600ms] ease-[cubic-bezier(.2,.7,.2,1)] group-hover:scale-105 group-focus-visible:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus-visible:scale-100" width="720" height="540" loading="lazy" alt="Jagged dark peaks behind a black sand beach and shallow tidal pools at sunrise"><span class="absolute inset-x-0 bottom-0 flex translate-y-2.5 flex-col gap-0.5 bg-linear-to-t from-[rgba(14,12,10,.88)] to-[rgba(14,12,10,0)] px-4 pt-12 pb-3.5 opacity-0 transition-[opacity,translate] duration-300 group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-none [@media(hover:none)]:translate-y-0 [@media(hover:none)]:opacity-100"><strong class="text-base font-semibold">Black sand at first light</strong><span class="text-[.8rem] text-[#ece7df]">East coast · 08:42</span></span></a></li>
    <li><a class="group relative block aspect-[4/3] overflow-hidden rounded-xl bg-[#d9d4cc] text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#a2461f]" href="https://images.unsplash.com/photo-1476610182048-b716b8518aae?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1476610182048-b716b8518aae?auto=format&fit=crop&w=720&h=540&q=70" class="block size-full object-cover transition-transform duration-[600ms] ease-[cubic-bezier(.2,.7,.2,1)] group-hover:scale-105 group-focus-visible:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus-visible:scale-100" width="720" height="540" loading="lazy" alt="A tall waterfall pouring off a green cliff into a pool, with a river winding across the plain at sunset"><span class="absolute inset-x-0 bottom-0 flex translate-y-2.5 flex-col gap-0.5 bg-linear-to-t from-[rgba(14,12,10,.88)] to-[rgba(14,12,10,0)] px-4 pt-12 pb-3.5 opacity-0 transition-[opacity,translate] duration-300 group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-none [@media(hover:none)]:translate-y-0 [@media(hover:none)]:opacity-100"><strong class="text-base font-semibold">The falls at sunset</strong><span class="text-[.8rem] text-[#ece7df]">South coast · 22:10</span></span></a></li>
    <li><a class="group relative block aspect-[4/3] overflow-hidden rounded-xl bg-[#d9d4cc] text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#a2461f]" href="https://images.unsplash.com/photo-1531168556467-80aace0d0144?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1531168556467-80aace0d0144?auto=format&fit=crop&w=720&h=540&q=70" class="block size-full object-cover transition-transform duration-[600ms] ease-[cubic-bezier(.2,.7,.2,1)] group-hover:scale-105 group-focus-visible:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus-visible:scale-100" width="720" height="540" loading="lazy" alt="A river running along the bottom of a deep, moss-covered canyon"><span class="absolute inset-x-0 bottom-0 flex translate-y-2.5 flex-col gap-0.5 bg-linear-to-t from-[rgba(14,12,10,.88)] to-[rgba(14,12,10,0)] px-4 pt-12 pb-3.5 opacity-0 transition-[opacity,translate] duration-300 group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-none [@media(hover:none)]:translate-y-0 [@media(hover:none)]:opacity-100"><strong class="text-base font-semibold">Moss canyon</strong><span class="text-[.8rem] text-[#ece7df]">South coast · 14:05</span></span></a></li>
    <li><a class="group relative block aspect-[4/3] overflow-hidden rounded-xl bg-[#d9d4cc] text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#a2461f]" href="https://images.unsplash.com/photo-1491466424936-e304919aada7?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1491466424936-e304919aada7?auto=format&fit=crop&w=720&h=540&q=70" class="block size-full object-cover transition-transform duration-[600ms] ease-[cubic-bezier(.2,.7,.2,1)] group-hover:scale-105 group-focus-visible:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus-visible:scale-100" width="720" height="540" loading="lazy" alt="A person with a headlamp standing at the mouth of a blue ice cave under a starry sky"><span class="absolute inset-x-0 bottom-0 flex translate-y-2.5 flex-col gap-0.5 bg-linear-to-t from-[rgba(14,12,10,.88)] to-[rgba(14,12,10,0)] px-4 pt-12 pb-3.5 opacity-0 transition-[opacity,translate] duration-300 group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-none [@media(hover:none)]:translate-y-0 [@media(hover:none)]:opacity-100"><strong class="text-base font-semibold">Inside the glacier</strong><span class="text-[.8rem] text-[#ece7df]">Southeast · 02:15</span></span></a></li>
    <li><a class="group relative block aspect-[4/3] overflow-hidden rounded-xl bg-[#d9d4cc] text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#a2461f]" href="https://images.unsplash.com/photo-1529963183134-61a90db47eaf?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1529963183134-61a90db47eaf?auto=format&fit=crop&w=720&h=540&q=70" class="block size-full object-cover transition-transform duration-[600ms] ease-[cubic-bezier(.2,.7,.2,1)] group-hover:scale-105 group-focus-visible:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus-visible:scale-100" width="720" height="540" loading="lazy" alt="Green aurora over a lagoon scattered with floating blocks of ice"><span class="absolute inset-x-0 bottom-0 flex translate-y-2.5 flex-col gap-0.5 bg-linear-to-t from-[rgba(14,12,10,.88)] to-[rgba(14,12,10,0)] px-4 pt-12 pb-3.5 opacity-0 transition-[opacity,translate] duration-300 group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-none [@media(hover:none)]:translate-y-0 [@media(hover:none)]:opacity-100"><strong class="text-base font-semibold">Aurora over the ice lagoon</strong><span class="text-[.8rem] text-[#ece7df]">Southeast · 23:40</span></span></a></li>
    <li><a class="group relative block aspect-[4/3] overflow-hidden rounded-xl bg-[#d9d4cc] text-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#a2461f]" href="https://images.unsplash.com/photo-1474690870753-1b92efa1f2d8?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1474690870753-1b92efa1f2d8?auto=format&fit=crop&w=720&h=540&q=70" class="block size-full object-cover transition-transform duration-[600ms] ease-[cubic-bezier(.2,.7,.2,1)] group-hover:scale-105 group-focus-visible:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus-visible:scale-100" width="720" height="540" loading="lazy" alt="A tall stepped concrete church tower under a blue sky, with people crossing the square in front"><span class="absolute inset-x-0 bottom-0 flex translate-y-2.5 flex-col gap-0.5 bg-linear-to-t from-[rgba(14,12,10,.88)] to-[rgba(14,12,10,0)] px-4 pt-12 pb-3.5 opacity-0 transition-[opacity,translate] duration-300 group-hover:translate-y-0 group-hover:opacity-100 group-focus-visible:translate-y-0 group-focus-visible:opacity-100 motion-reduce:transition-none [@media(hover:none)]:translate-y-0 [@media(hover:none)]:opacity-100"><strong class="text-base font-semibold">Hallgrímskirkja</strong><span class="text-[.8rem] text-[#ece7df]">Reykjavík · 11:20</span></span></a></li>
  </ul>
</section></div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#625c53] uppercase">Square tiles with captions underneath</span>
<section aria-labelledby="sq-title">
  <div class="mb-5 flex flex-wrap items-end justify-between gap-x-6 gap-y-1.5"><div><p class="text-xs leading-[normal] font-bold tracking-[.14em] text-[#a2461f] uppercase">Still Water</p><h2 id="sq-title" class="mt-1 text-[1.75rem] leading-[1.15] font-bold tracking-[-.02em]">Alpine lakes</h2></div><p class="text-[.9rem] leading-[normal] text-[#625c53]">8 photographs · Mara Lind</p></div>
  <ul class="grid grid-cols-2 gap-x-4 gap-y-6 md:grid-cols-4" role="list">
    <li><figure><img src="https://images.unsplash.com/photo-1501785888041-af3ef285b470?auto=format&fit=crop&w=480&h=480&q=70" class="block aspect-square w-full rounded-[10px] bg-[#d9d4cc] object-cover" width="480" height="480" loading="lazy" alt="A rowing boat on a turquoise lake below steep rocky mountains"><figcaption class="mt-2.5"><span class="block text-[.95rem] font-semibold">Morning row</span><span class="mt-0.5 block text-[.8rem] text-[#625c53]">June 14, 07:10</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1470770841072-f978cf4d019e?auto=format&fit=crop&w=480&h=480&q=70" class="block aspect-square w-full rounded-[10px] bg-[#d9d4cc] object-cover" width="480" height="480" loading="lazy" alt="A wooden boathouse on stilts in a green lake beneath cloud-wrapped peaks"><figcaption class="mt-2.5"><span class="block text-[.95rem] font-semibold">The boathouse</span><span class="mt-0.5 block text-[.8rem] text-[#625c53]">June 14, 09:30</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&w=480&h=480&q=70" class="block aspect-square w-full rounded-[10px] bg-[#d9d4cc] object-cover" width="480" height="480" loading="lazy" alt="The bow of a wooden boat on green water, facing grey limestone mountains"><figcaption class="mt-2.5"><span class="block text-[.95rem] font-semibold">From the bow</span><span class="mt-0.5 block text-[.8rem] text-[#625c53]">June 15, 08:05</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1493246507139-91e8fad9978e?auto=format&fit=crop&w=480&h=480&q=70" class="block aspect-square w-full rounded-[10px] bg-[#d9d4cc] object-cover" width="480" height="480" loading="lazy" alt="A turquoise lake reflecting jagged peaks lit pink at sunrise"><figcaption class="mt-2.5"><span class="block text-[.95rem] font-semibold">Pink peaks</span><span class="mt-0.5 block text-[.8rem] text-[#625c53]">July 2, 05:48</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1473448912268-2022ce9509d8?auto=format&fit=crop&w=480&h=480&q=70" class="block aspect-square w-full rounded-[10px] bg-[#d9d4cc] object-cover" width="480" height="480" loading="lazy" alt="Tall pines along a still green river, with mountains fading into mist"><figcaption class="mt-2.5"><span class="block text-[.95rem] font-semibold">River in the pines</span><span class="mt-0.5 block text-[.8rem] text-[#625c53]">July 3, 10:15</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?auto=format&fit=crop&w=480&h=480&q=70" class="block aspect-square w-full rounded-[10px] bg-[#d9d4cc] object-cover" width="480" height="480" loading="lazy" alt="A wooden jetty stretching into a calm blue lake lined with forest"><figcaption class="mt-2.5"><span class="block text-[.95rem] font-semibold">The jetty</span><span class="mt-0.5 block text-[.8rem] text-[#625c53]">July 4, 12:30</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1494500764479-0c8f2919a3d8?auto=format&fit=crop&w=480&h=480&q=70" class="block aspect-square w-full rounded-[10px] bg-[#d9d4cc] object-cover" width="480" height="480" loading="lazy" alt="A lone tree standing in a still lake under a purple dusk sky"><figcaption class="mt-2.5"><span class="block text-[.95rem] font-semibold">The lone tree</span><span class="mt-0.5 block text-[.8rem] text-[#625c53]">August 9, 20:55</span></figcaption></figure></li>
    <li><figure><img src="https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?auto=format&fit=crop&w=480&h=480&q=70" class="block aspect-square w-full rounded-[10px] bg-[#d9d4cc] object-cover" width="480" height="480" loading="lazy" alt="A pine forest and a wide glacial valley below snowy mountains"><figcaption class="mt-2.5"><span class="block text-[.95rem] font-semibold">Valley lookout</span><span class="mt-0.5 block text-[.8rem] text-[#625c53]">August 10, 16:40</span></figcaption></figure></li>
  </ul>
</section></div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#625c53] uppercase">Featured photo grid</span>
<section aria-labelledby="fg-title">
  <div class="mb-5 flex flex-wrap items-end justify-between gap-x-6 gap-y-1.5"><div><p class="text-xs leading-[normal] font-bold tracking-[.14em] text-[#a2461f] uppercase">Vertical City</p><h2 id="fg-title" class="mt-1 text-[1.75rem] leading-[1.15] font-bold tracking-[-.02em]">Looking up</h2></div><p class="text-[.9rem] leading-[normal] text-[#625c53]">5 photographs · Lena Ortiz</p></div>
  <ul class="grid grid-cols-2 gap-4 md:grid-cols-4" role="list">
    <li class="col-span-2 row-span-2"><a class="group relative block aspect-square overflow-hidden rounded-[14px] bg-[#d9d4cc] text-[#1d1b18] focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#a2461f]" href="https://images.unsplash.com/photo-1511818966892-d7d671e672a2?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1511818966892-d7d671e672a2?auto=format&fit=crop&w=960&h=960&q=70" class="block size-full object-cover transition-transform duration-[600ms] ease-[cubic-bezier(.2,.7,.2,1)] group-hover:scale-105 group-focus-visible:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus-visible:scale-100" width="960" height="960" loading="lazy" alt="Looking straight up between glass skyscrapers under a heavy grey sky, in black and white"><span class="absolute rounded-full bg-white/94 font-semibold bottom-4 left-4 px-4 py-2 text-[.95rem]">Glass canyon<small class="ml-2 text-xs font-medium text-[#625c53]">Plate 01</small></span></a></li>
    <li><a class="group relative block aspect-square overflow-hidden rounded-[14px] bg-[#d9d4cc] text-[#1d1b18] focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#a2461f]" href="https://images.unsplash.com/photo-1431576901776-e539bd916ba2?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1431576901776-e539bd916ba2?auto=format&fit=crop&w=480&h=480&q=70" class="block size-full object-cover transition-transform duration-[600ms] ease-[cubic-bezier(.2,.7,.2,1)] group-hover:scale-105 group-focus-visible:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus-visible:scale-100" width="480" height="480" loading="lazy" alt="Two glass towers seen from below, their windows glowing orange against a white sky"><span class="absolute rounded-full bg-white/94 font-semibold bottom-3 left-3 px-3 py-1.5 text-[.8rem]">Amber</span></a></li>
    <li><a class="group relative block aspect-square overflow-hidden rounded-[14px] bg-[#d9d4cc] text-[#1d1b18] focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#a2461f]" href="https://images.unsplash.com/photo-1449824913935-59a10b8d2000?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1449824913935-59a10b8d2000?auto=format&fit=crop&w=480&h=480&q=70" class="block size-full object-cover transition-transform duration-[600ms] ease-[cubic-bezier(.2,.7,.2,1)] group-hover:scale-105 group-focus-visible:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus-visible:scale-100" width="480" height="480" loading="lazy" alt="A wide avenue lined with tall buildings, with yellow taxis waiting at the lights"><span class="absolute rounded-full bg-white/94 font-semibold bottom-3 left-3 px-3 py-1.5 text-[.8rem]">Avenue</span></a></li>
    <li><a class="group relative block aspect-square overflow-hidden rounded-[14px] bg-[#d9d4cc] text-[#1d1b18] focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#a2461f]" href="https://images.unsplash.com/photo-1519501025264-65ba15a82390?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1519501025264-65ba15a82390?auto=format&fit=crop&w=480&h=480&q=70" class="block size-full object-cover transition-transform duration-[600ms] ease-[cubic-bezier(.2,.7,.2,1)] group-hover:scale-105 group-focus-visible:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus-visible:scale-100" width="480" height="480" loading="lazy" alt="A wet street at dusk between dark towers, with car lights reflected on the road"><span class="absolute rounded-full bg-white/94 font-semibold bottom-3 left-3 px-3 py-1.5 text-[.8rem]">Rain hour</span></a></li>
    <li><a class="group relative block aspect-square overflow-hidden rounded-[14px] bg-[#d9d4cc] text-[#1d1b18] focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#a2461f]" href="https://images.unsplash.com/photo-1514565131-fce0801e5785?auto=format&fit=crop&w=2000&q=70"><img src="https://images.unsplash.com/photo-1514565131-fce0801e5785?auto=format&fit=crop&w=480&h=480&q=70" class="block size-full object-cover transition-transform duration-[600ms] ease-[cubic-bezier(.2,.7,.2,1)] group-hover:scale-105 group-focus-visible:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100 motion-reduce:group-focus-visible:scale-100" width="480" height="480" loading="lazy" alt="A downtown skyline with one tall spire across the water at dusk, the moon above it"><span class="absolute rounded-full bg-white/94 font-semibold bottom-3 left-3 px-3 py-1.5 text-[.8rem]">Across the river</span></a></li>
  </ul>
</section></div>

About this set

Three photo grids for the most common gallery job: showing a set of pictures in tidy rows. Captions on hover and focus is a 4:3 grid of six Iceland landscapes, one column on phones, two on tablets and three on desktops; each tile links to the full-size photo, zooms slightly and slides up a caption with a title and a place when it is hovered or reached with the Tab key, and on touch screens the captions are simply always shown. Square tiles with captions underneath lays out eight lake photos in a four-up grid with the title and date printed below each square, for galleries where the words matter as much as the pictures. Featured photo grid gives the first photo a double-size square beside four smaller ones, with a white label pill on each, for a cover image and its supporting shots. The plain CSS version is CSS Grid with aspect-ratio and object-fit, the Bootstrap version uses .row-cols-* and the .ratio helper, and the Tailwind version uses grid, aspect and group-hover utilities. None of it needs JavaScript.

What’s included

  • Three layouts: hover-caption grid, captioned squares and a featured photo grid
  • Captions appear on hover and on keyboard focus, and always on touch screens
  • Columns step from one to two to three without cropping the aspect ratio
  • Each tile links to the full-size photo, so it works without any script
  • Bootstrap version built from .row-cols-*, .ratio and .figure

Accessibility

Every photo has alt text that describes what is in it, and the visible captions add the title and place rather than repeating it. Each tile is a link with a 3px outline on keyboard focus, and the hover caption also appears on focus, so nothing is reachable by mouse alone. The zoom and caption transitions are switched off under prefers-reduced-motion.

Customise it

Change --gg-gap, --gg-radius, --gg-ratio and --gg-focus on .gg, and the grid-template-columns breakpoints for the column count. In Bootstrap swap .ratio-4x3 or .row-cols-lg-3; in Tailwind edit aspect-[4/3] and the min-[992px]:grid-cols-3 utility.