Open demo

CSS code

HTML
<div class="full"><span class="lbl">Grayscale to colour</span>
<div class="fx-team">
  <a href="#" class="fx fx-gray"><span class="fx-frame"><img src="https://images.unsplash.com/photo-1580489944761-15a19d654956?auto=format&fit=crop&w=600&h=750&q=70" alt="Portrait of Maya Lindqvist" width="600" height="750"></span>
    <span class="fx-cap"><span class="fx-title">Maya Lindqvist</span><span class="fx-sub">Editor in chief</span></span></a>
  <a href="#" class="fx fx-gray"><span class="fx-frame"><img src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=600&h=750&q=70" alt="Portrait of Rafael Mendoza" width="600" height="750"></span>
    <span class="fx-cap"><span class="fx-title">Rafael Mendoza</span><span class="fx-sub">Photo editor</span></span></a>
  <a href="#" class="fx fx-gray"><span class="fx-frame"><img src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=600&h=750&q=70" alt="Portrait of Chloe Bennett" width="600" height="750"></span>
    <span class="fx-cap"><span class="fx-title">Chloe Bennett</span><span class="fx-sub">Travel writer</span></span></a>
</div></div>
<div><span class="lbl">Duotone to full colour</span>
<a href="#" class="fx fx-duo"><span class="fx-frame"><img src="https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?auto=format&fit=crop&w=900&h=675&q=70" alt="Aerial view of Chicago skyscrapers beside the blue lake" width="900" height="675"></span>
  <span class="fx-cap"><span class="fx-title">Chicago From Above</span><span class="fx-sub">Photo essay · 18 images</span></span></a></div>
<div><span class="lbl">Blur to sharp</span>
<a href="#" class="fx fx-blur"><span class="fx-frame"><img src="https://images.unsplash.com/photo-1540959733332-eab4deabeeaf?auto=format&fit=crop&w=900&h=675&q=70" alt="A Tokyo shopping street lit by neon signs at dusk" width="900" height="675"></span>
  <span class="fx-cap"><span class="fx-title">Tokyo After Rain</span><span class="fx-sub">Photo essay · 24 images</span></span></a></div>
<div><span class="lbl">Sepia to colour</span>
<a href="#" class="fx fx-sepia"><span class="fx-frame"><img src="https://images.unsplash.com/photo-1502602898657-3e91760cbb34?auto=format&fit=crop&w=900&h=675&q=70" alt="The Eiffel Tower above the Seine under a violet evening sky" width="900" height="675"></span>
  <span class="fx-cap"><span class="fx-title">Paris at Blue Hour</span><span class="fx-sub">Photo essay · 12 images</span></span></a></div>
<div><span class="lbl">Circle mask reveal</span>
<a href="#" class="fx fx-circle"><span class="fx-frame"><img src="https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&w=900&h=675&q=70" alt="The bow of a wooden rowing boat on a green mountain lake" width="900" height="675"><img class="fx-top" src="https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&w=900&h=675&q=70" alt="" width="900" height="675"></span>
  <span class="fx-cap"><span class="fx-title">Still Water, Wooden Boats</span><span class="fx-sub">Photo essay · 15 images</span></span></a></div>
<div class="full"><span class="lbl">Diagonal clip-path wipe</span>
<a href="#" class="fx fx-wipe"><span class="fx-frame"><img src="https://images.unsplash.com/photo-1513635269975-59663e0ac1ad?auto=format&fit=crop&w=1600&h=686&q=70" alt="Aerial view of London with Tower Bridge crossing the Thames" width="1600" height="686">
  <span class="fx-panel"><i>City guide</i><b>14 routes, 3 to 9 km</b><span>Step-free options and cafés marked on every map.</span></span></span>
  <span class="fx-cap"><span class="fx-title">London in Fourteen Walks</span><span class="fx-sub">Guide · updated October 2026</span></span></a></div>
CSS
/* Filter and mask hover effects. Filters and opacity are not motion, so they keep their fades under
   reduced motion; the clip-path reveals switch instantly instead. Touch screens (hover: none) get the
   finished state straight away. */
.fx{--fx-accent:#4338ca;--fx-ink:#161a2b;--fx-muted:#4a5068;--fx-radius:16px;--fx-speed:.6s;--fx-ease:cubic-bezier(.3,.7,.2,1);
  display:block;border-radius:var(--fx-radius);color:var(--fx-ink);text-decoration:none}
.fx:focus-visible{outline:3px solid var(--fx-accent);outline-offset:5px}
.fx-frame{position:relative;display:block;aspect-ratio:4/3;overflow:hidden;border-radius:var(--fx-radius);background:#d5d9e3;isolation:isolate}
.fx-frame img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transition:filter var(--fx-speed)}
.fx-cap{display:grid;gap:2px;padding:14px 2px 0;line-height:1.4}
.fx-title{font-size:1.05rem;font-weight:700;text-decoration:underline 2px transparent;text-underline-offset:4px;transition:text-decoration-color .3s}
.fx-sub{font-size:.88rem;color:var(--fx-muted)}
.fx:is(:hover,:focus-visible) .fx-title{text-decoration-color:var(--fx-accent)}

/* 1. Grayscale to colour (team grid) */
.fx-team{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.fx-gray .fx-frame{aspect-ratio:4/5}
.fx-gray img{filter:grayscale(1) contrast(1.05)}
.fx-gray:is(:hover,:focus-visible) img{filter:none}

/* 2. Duotone: a grey photo, a light colour multiplied in and a dark colour lightened in */
.fx-duo{--fx-light:#fbcfe8;--fx-dark:#312e81}
.fx-duo img{filter:grayscale(1) contrast(1.15)}
.fx-duo .fx-frame::before,.fx-duo .fx-frame::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;transition:opacity var(--fx-speed)}
.fx-duo .fx-frame::before{background:var(--fx-light);mix-blend-mode:multiply}
.fx-duo .fx-frame::after{background:var(--fx-dark);mix-blend-mode:lighten}
.fx-duo:is(:hover,:focus-visible) img{filter:none}
.fx-duo:is(:hover,:focus-visible) .fx-frame::before,.fx-duo:is(:hover,:focus-visible) .fx-frame::after{opacity:0}

/* 3. Blur to sharp (scaled a little so the blurred edge never shows) */
.fx-blur img{filter:blur(6px) saturate(.85);transform:scale(1.06)}
.fx-blur:is(:hover,:focus-visible) img{filter:none}

/* 4. Sepia to colour */
.fx-sepia img{filter:sepia(.85) contrast(.95) brightness(1.03)}
.fx-sepia:is(:hover,:focus-visible) img{filter:none}

/* 5. Circle mask: a colour copy of the photo, clipped to a small porthole, opens to the full frame */
.fx-circle img:first-child{filter:grayscale(1) brightness(.8)}
.fx-circle .fx-top{clip-path:circle(17% at 50% 50%);transition:clip-path .7s var(--fx-ease)}
.fx-circle:is(:hover,:focus-visible) .fx-top{clip-path:circle(75% at 50% 50%)}

/* 6. Diagonal wipe: a slanted panel slides its edge across with clip-path */
.fx-wipe .fx-frame{aspect-ratio:21/9}
.fx-panel{position:absolute;inset:0;z-index:1;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:8px;
  padding:0 48% 0 clamp(20px,5vw,48px);background:rgba(49,46,129,.94);color:#fff;line-height:1.4;
  clip-path:polygon(0 0,0 0,0 100%,0 100%);transition:clip-path .7s var(--fx-ease)}
.fx-panel b{font-size:clamp(1.15rem,2.4vw,1.6rem);line-height:1.15}
.fx-panel span{font-size:.92rem;color:#e0e7ff}
.fx-panel i{font-style:normal;font-size:.72rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:#c7d2fe}
.fx-wipe:is(:hover,:focus-visible) .fx-panel{clip-path:polygon(0 0,64% 0,52% 100%,0 100%)}
@media (max-width:767px){
  .fx-wipe .fx-frame{aspect-ratio:4/3}
  .fx-panel{padding-right:22%}
  .fx-wipe:is(:hover,:focus-visible) .fx-panel{clip-path:polygon(0 0,92% 0,80% 100%,0 100%)}
}

/* Touch screens: show the finished state */
@media (hover:none){
  .fx .fx-frame img{filter:none}
  .fx-duo .fx-frame::before,.fx-duo .fx-frame::after{opacity:0}
  .fx-circle .fx-top{clip-path:none}
  .fx-wipe .fx-panel{clip-path:polygon(0 0,64% 0,52% 100%,0 100%)}
}
@media (hover:none) and (max-width:767px){.fx-wipe .fx-panel{clip-path:polygon(0 0,92% 0,80% 100%,0 100%)}}
/* Reduced motion: the clip-path reveals switch without animating; filter fades stay */
@media (prefers-reduced-motion:reduce){
  .fx-top,.fx-panel{transition:none}
}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div class="row gx-4 gy-5">
<div class="col-12"><span class="lbl">Grayscale to colour</span>
<div class="row row-cols-3 g-3">
  <div class="col"><a href="#" class="fx fx-gray"><figure class="figure d-block m-0"><span class="ratio fx-frame d-block" style="--bs-aspect-ratio:125%"><img src="https://images.unsplash.com/photo-1580489944761-15a19d654956?auto=format&fit=crop&w=600&h=750&q=70" alt="Portrait of Maya Lindqvist" width="600" height="750"></span>
    <figcaption class="figure-caption fx-cap"><span class="fx-title">Maya Lindqvist</span><span class="fx-sub">Editor in chief</span></figcaption></figure></a></div>
  <div class="col"><a href="#" class="fx fx-gray"><figure class="figure d-block m-0"><span class="ratio fx-frame d-block" style="--bs-aspect-ratio:125%"><img src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=600&h=750&q=70" alt="Portrait of Rafael Mendoza" width="600" height="750"></span>
    <figcaption class="figure-caption fx-cap"><span class="fx-title">Rafael Mendoza</span><span class="fx-sub">Photo editor</span></figcaption></figure></a></div>
  <div class="col"><a href="#" class="fx fx-gray"><figure class="figure d-block m-0"><span class="ratio fx-frame d-block" style="--bs-aspect-ratio:125%"><img src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=600&h=750&q=70" alt="Portrait of Chloe Bennett" width="600" height="750"></span>
    <figcaption class="figure-caption fx-cap"><span class="fx-title">Chloe Bennett</span><span class="fx-sub">Travel writer</span></figcaption></figure></a></div>
</div></div>
<div class="col-md-6"><span class="lbl">Duotone to full colour</span>
<a href="#" class="fx fx-duo"><figure class="figure d-block m-0"><span class="ratio ratio-4x3 fx-frame d-block"><img src="https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?auto=format&fit=crop&w=900&h=675&q=70" alt="Aerial view of Chicago skyscrapers beside the blue lake" width="900" height="675"><span class="fx-tone" aria-hidden="true"></span></span>
  <figcaption class="figure-caption fx-cap"><span class="fx-title">Chicago From Above</span><span class="fx-sub">Photo essay · 18 images</span></figcaption></figure></a></div>
<div class="col-md-6"><span class="lbl">Blur to sharp</span>
<a href="#" class="fx fx-blur"><figure class="figure d-block m-0"><span class="ratio ratio-4x3 fx-frame d-block"><img src="https://images.unsplash.com/photo-1540959733332-eab4deabeeaf?auto=format&fit=crop&w=900&h=675&q=70" alt="A Tokyo shopping street lit by neon signs at dusk" width="900" height="675"></span>
  <figcaption class="figure-caption fx-cap"><span class="fx-title">Tokyo After Rain</span><span class="fx-sub">Photo essay · 24 images</span></figcaption></figure></a></div>
<div class="col-md-6"><span class="lbl">Sepia to colour</span>
<a href="#" class="fx fx-sepia"><figure class="figure d-block m-0"><span class="ratio ratio-4x3 fx-frame d-block"><img src="https://images.unsplash.com/photo-1502602898657-3e91760cbb34?auto=format&fit=crop&w=900&h=675&q=70" alt="The Eiffel Tower above the Seine under a violet evening sky" width="900" height="675"></span>
  <figcaption class="figure-caption fx-cap"><span class="fx-title">Paris at Blue Hour</span><span class="fx-sub">Photo essay · 12 images</span></figcaption></figure></a></div>
<div class="col-md-6"><span class="lbl">Circle mask reveal</span>
<a href="#" class="fx fx-circle"><figure class="figure d-block m-0"><span class="ratio ratio-4x3 fx-frame d-block"><img src="https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&w=900&h=675&q=70" alt="The bow of a wooden rowing boat on a green mountain lake" width="900" height="675"><img class="fx-top" src="https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&w=900&h=675&q=70" alt="" width="900" height="675"></span>
  <figcaption class="figure-caption fx-cap"><span class="fx-title">Still Water, Wooden Boats</span><span class="fx-sub">Photo essay · 15 images</span></figcaption></figure></a></div>
<div class="col-12"><span class="lbl">Diagonal clip-path wipe</span>
<a href="#" class="fx fx-wipe"><figure class="figure d-block m-0"><span class="ratio ratio-21x9 fx-frame d-block"><img src="https://images.unsplash.com/photo-1513635269975-59663e0ac1ad?auto=format&fit=crop&w=1600&h=686&q=70" alt="Aerial view of London with Tower Bridge crossing the Thames" width="1600" height="686">
  <span class="fx-panel"><i>City guide</i><b>14 routes, 3 to 9 km</b><span>Step-free options and cafés marked on every map.</span></span></span>
  <figcaption class="figure-caption fx-cap"><span class="fx-title">London in Fourteen Walks</span><span class="fx-sub">Guide · updated October 2026</span></figcaption></figure></a></div>
</div>
CSS
/* Bootstrap .figure, .figure-caption and .ratio frames. Filter and mask hover effects. Filters and opacity are not motion, so they keep their fades under
   reduced motion; the clip-path reveals switch instantly instead. Touch screens (hover: none) get the
   finished state straight away. */
.fx{--fx-accent:#4338ca;--fx-ink:#161a2b;--fx-muted:#4a5068;--fx-radius:16px;--fx-speed:.6s;--fx-ease:cubic-bezier(.3,.7,.2,1);
  display:block;border-radius:var(--fx-radius);color:var(--fx-ink);text-decoration:none}
.fx:focus-visible{outline:3px solid var(--fx-accent);outline-offset:5px}
.fx-frame{overflow:hidden;border-radius:var(--fx-radius);background:#d5d9e3;isolation:isolate}
.fx-frame img{object-fit:cover;transition:filter var(--fx-speed)}
.fx-cap{display:grid;gap:2px;margin:0;padding:14px 2px 0;font-size:1rem;color:inherit;line-height:1.4}
.fx-title{font-size:1.05rem;font-weight:700;text-decoration:underline 2px transparent;text-underline-offset:4px;transition:text-decoration-color .3s}
.fx-sub{font-size:.88rem;color:var(--fx-muted)}
.fx:is(:hover,:focus-visible) .fx-title{text-decoration-color:var(--fx-accent)}

/* 1. Grayscale to colour (team grid) */
.fx-gray img{filter:grayscale(1) contrast(1.05)}
.fx-gray:is(:hover,:focus-visible) img{filter:none}

/* 2. Duotone: a grey photo, a light colour multiplied in (.fx-tone, because .ratio owns ::before) and a dark colour lightened in */
.fx-duo{--fx-light:#fbcfe8;--fx-dark:#312e81}
.fx-duo img{filter:grayscale(1) contrast(1.15)}
.fx-duo .fx-tone,.fx-duo .fx-frame::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;transition:opacity var(--fx-speed)}
.fx-duo .fx-tone{background:var(--fx-light);mix-blend-mode:multiply}
.fx-duo .fx-frame::after{background:var(--fx-dark);mix-blend-mode:lighten}
.fx-duo:is(:hover,:focus-visible) img{filter:none}
.fx-duo:is(:hover,:focus-visible) .fx-tone,.fx-duo:is(:hover,:focus-visible) .fx-frame::after{opacity:0}

/* 3. Blur to sharp (scaled a little so the blurred edge never shows) */
.fx-blur img{filter:blur(6px) saturate(.85);transform:scale(1.06)}
.fx-blur:is(:hover,:focus-visible) img{filter:none}

/* 4. Sepia to colour */
.fx-sepia img{filter:sepia(.85) contrast(.95) brightness(1.03)}
.fx-sepia:is(:hover,:focus-visible) img{filter:none}

/* 5. Circle mask: a colour copy of the photo, clipped to a small porthole, opens to the full frame */
.fx-circle img:first-child{filter:grayscale(1) brightness(.8)}
.fx-circle .fx-top{clip-path:circle(17% at 50% 50%);transition:clip-path .7s var(--fx-ease)}
.fx-circle:is(:hover,:focus-visible) .fx-top{clip-path:circle(75% at 50% 50%)}

/* 6. Diagonal wipe: a slanted panel slides its edge across with clip-path */
.fx-panel{z-index:1;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:8px;
  padding:0 48% 0 clamp(20px,5vw,48px);background:rgba(49,46,129,.94);color:#fff;line-height:1.4;
  clip-path:polygon(0 0,0 0,0 100%,0 100%);transition:clip-path .7s var(--fx-ease)}
.fx-panel b{font-size:clamp(1.15rem,2.4vw,1.6rem);line-height:1.15}
.fx-panel span{font-size:.92rem;color:#e0e7ff}
.fx-panel i{font-style:normal;font-size:.72rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:#c7d2fe}
.fx-wipe:is(:hover,:focus-visible) .fx-panel{clip-path:polygon(0 0,64% 0,52% 100%,0 100%)}
@media (max-width:767px){
  .fx-wipe .fx-frame{--bs-aspect-ratio:75%}
  .fx-panel{padding-right:22%}
  .fx-wipe:is(:hover,:focus-visible) .fx-panel{clip-path:polygon(0 0,92% 0,80% 100%,0 100%)}
}

/* Touch screens: show the finished state */
@media (hover:none){
  .fx .fx-frame img{filter:none}
  .fx-duo .fx-tone,.fx-duo .fx-frame::after{opacity:0}
  .fx-circle .fx-top{clip-path:none}
  .fx-wipe .fx-panel{clip-path:polygon(0 0,64% 0,52% 100%,0 100%)}
}
@media (hover:none) and (max-width:767px){.fx-wipe .fx-panel{clip-path:polygon(0 0,92% 0,80% 100%,0 100%)}}
/* Reduced motion: the clip-path reveals switch without animating; filter fades stay */
@media (prefers-reduced-motion:reduce){
  .fx-top,.fx-panel{transition:none}
}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div class="grid grid-cols-1 gap-x-7 gap-y-12 md:grid-cols-2">
<div class="md:col-span-2"><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#525872] uppercase">Grayscale to colour</span>
<div class="grid grid-cols-3 gap-4">
  <a href="#" class="group block rounded-2xl text-ink no-underline focus-visible:outline-3 focus-visible:outline-offset-5 focus-visible:outline-indigo"><span class="relative isolate block overflow-hidden rounded-2xl bg-[#d5d9e3] aspect-[4/5] "><img class="absolute inset-0 size-full object-cover transition-[filter] duration-600 grayscale contrast-105 group-hover:filter-none group-focus-visible:filter-none touch:filter-none!" src="https://images.unsplash.com/photo-1580489944761-15a19d654956?auto=format&fit=crop&w=600&h=750&q=70" alt="Portrait of Maya Lindqvist" width="600" height="750"></span>
  <span class="grid gap-0.5 px-0.5 pt-3.5 leading-[1.4]"><span class="text-[1.05rem] font-bold underline decoration-transparent decoration-2 underline-offset-4 transition-[text-decoration-color] duration-300 group-hover:decoration-indigo group-focus-visible:decoration-indigo">Maya Lindqvist</span><span class="text-[.88rem] text-muted">Editor in chief</span></span></a>
  <a href="#" class="group block rounded-2xl text-ink no-underline focus-visible:outline-3 focus-visible:outline-offset-5 focus-visible:outline-indigo"><span class="relative isolate block overflow-hidden rounded-2xl bg-[#d5d9e3] aspect-[4/5] "><img class="absolute inset-0 size-full object-cover transition-[filter] duration-600 grayscale contrast-105 group-hover:filter-none group-focus-visible:filter-none touch:filter-none!" src="https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?auto=format&fit=crop&w=600&h=750&q=70" alt="Portrait of Rafael Mendoza" width="600" height="750"></span>
  <span class="grid gap-0.5 px-0.5 pt-3.5 leading-[1.4]"><span class="text-[1.05rem] font-bold underline decoration-transparent decoration-2 underline-offset-4 transition-[text-decoration-color] duration-300 group-hover:decoration-indigo group-focus-visible:decoration-indigo">Rafael Mendoza</span><span class="text-[.88rem] text-muted">Photo editor</span></span></a>
  <a href="#" class="group block rounded-2xl text-ink no-underline focus-visible:outline-3 focus-visible:outline-offset-5 focus-visible:outline-indigo"><span class="relative isolate block overflow-hidden rounded-2xl bg-[#d5d9e3] aspect-[4/5] "><img class="absolute inset-0 size-full object-cover transition-[filter] duration-600 grayscale contrast-105 group-hover:filter-none group-focus-visible:filter-none touch:filter-none!" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=600&h=750&q=70" alt="Portrait of Chloe Bennett" width="600" height="750"></span>
  <span class="grid gap-0.5 px-0.5 pt-3.5 leading-[1.4]"><span class="text-[1.05rem] font-bold underline decoration-transparent decoration-2 underline-offset-4 transition-[text-decoration-color] duration-300 group-hover:decoration-indigo group-focus-visible:decoration-indigo">Chloe Bennett</span><span class="text-[.88rem] text-muted">Travel writer</span></span></a>
</div></div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#525872] uppercase">Duotone to full colour</span>
<a href="#" class="group block rounded-2xl text-ink no-underline focus-visible:outline-3 focus-visible:outline-offset-5 focus-visible:outline-indigo"><span class="relative isolate block overflow-hidden rounded-2xl bg-[#d5d9e3] aspect-[4/3] before:absolute before:inset-0 before:z-1 before:pointer-events-none before:bg-[#fbcfe8] before:mix-blend-multiply before:transition-opacity before:duration-600 after:absolute after:inset-0 after:z-1 after:pointer-events-none after:bg-[#312e81] after:mix-blend-lighten after:transition-opacity after:duration-600 group-hover:before:opacity-0 group-focus-visible:before:opacity-0 group-hover:after:opacity-0 group-focus-visible:after:opacity-0 touch:before:opacity-0 touch:after:opacity-0"><img class="absolute inset-0 size-full object-cover transition-[filter] duration-600 grayscale contrast-115 group-hover:filter-none group-focus-visible:filter-none touch:filter-none!" src="https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?auto=format&fit=crop&w=900&h=675&q=70" alt="Aerial view of Chicago skyscrapers beside the blue lake" width="900" height="675"></span>
  <span class="grid gap-0.5 px-0.5 pt-3.5 leading-[1.4]"><span class="text-[1.05rem] font-bold underline decoration-transparent decoration-2 underline-offset-4 transition-[text-decoration-color] duration-300 group-hover:decoration-indigo group-focus-visible:decoration-indigo">Chicago From Above</span><span class="text-[.88rem] text-muted">Photo essay · 18 images</span></span></a></div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#525872] uppercase">Blur to sharp</span>
<a href="#" class="group block rounded-2xl text-ink no-underline focus-visible:outline-3 focus-visible:outline-offset-5 focus-visible:outline-indigo"><span class="relative isolate block overflow-hidden rounded-2xl bg-[#d5d9e3] aspect-[4/3] "><img class="absolute inset-0 size-full object-cover transition-[filter] duration-600 scale-106 blur-[6px] saturate-85 group-hover:filter-none group-focus-visible:filter-none touch:filter-none!" src="https://images.unsplash.com/photo-1540959733332-eab4deabeeaf?auto=format&fit=crop&w=900&h=675&q=70" alt="A Tokyo shopping street lit by neon signs at dusk" width="900" height="675"></span>
  <span class="grid gap-0.5 px-0.5 pt-3.5 leading-[1.4]"><span class="text-[1.05rem] font-bold underline decoration-transparent decoration-2 underline-offset-4 transition-[text-decoration-color] duration-300 group-hover:decoration-indigo group-focus-visible:decoration-indigo">Tokyo After Rain</span><span class="text-[.88rem] text-muted">Photo essay · 24 images</span></span></a></div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#525872] uppercase">Sepia to colour</span>
<a href="#" class="group block rounded-2xl text-ink no-underline focus-visible:outline-3 focus-visible:outline-offset-5 focus-visible:outline-indigo"><span class="relative isolate block overflow-hidden rounded-2xl bg-[#d5d9e3] aspect-[4/3] "><img class="absolute inset-0 size-full object-cover transition-[filter] duration-600 sepia-85 contrast-95 brightness-103 group-hover:filter-none group-focus-visible:filter-none touch:filter-none!" src="https://images.unsplash.com/photo-1502602898657-3e91760cbb34?auto=format&fit=crop&w=900&h=675&q=70" alt="The Eiffel Tower above the Seine under a violet evening sky" width="900" height="675"></span>
  <span class="grid gap-0.5 px-0.5 pt-3.5 leading-[1.4]"><span class="text-[1.05rem] font-bold underline decoration-transparent decoration-2 underline-offset-4 transition-[text-decoration-color] duration-300 group-hover:decoration-indigo group-focus-visible:decoration-indigo">Paris at Blue Hour</span><span class="text-[.88rem] text-muted">Photo essay · 12 images</span></span></a></div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#525872] uppercase">Circle mask reveal</span>
<a href="#" class="group block rounded-2xl text-ink no-underline focus-visible:outline-3 focus-visible:outline-offset-5 focus-visible:outline-indigo"><span class="relative isolate block overflow-hidden rounded-2xl bg-[#d5d9e3] aspect-[4/3] "><img class="absolute inset-0 size-full object-cover transition-[filter] duration-600 grayscale brightness-80 group-hover:filter-none group-focus-visible:filter-none touch:filter-none!" src="https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&w=900&h=675&q=70" alt="The bow of a wooden rowing boat on a green mountain lake" width="900" height="675"><img class="absolute inset-0 size-full object-cover [clip-path:circle(17%_at_50%_50%)] transition-[clip-path] duration-700 ease-[cubic-bezier(.3,.7,.2,1)] group-hover:[clip-path:circle(75%_at_50%_50%)] group-focus-visible:[clip-path:circle(75%_at_50%_50%)] touch:[clip-path:none]! motion-reduce:transition-none" src="https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&w=900&h=675&q=70" alt="" width="900" height="675"></span>
  <span class="grid gap-0.5 px-0.5 pt-3.5 leading-[1.4]"><span class="text-[1.05rem] font-bold underline decoration-transparent decoration-2 underline-offset-4 transition-[text-decoration-color] duration-300 group-hover:decoration-indigo group-focus-visible:decoration-indigo">Still Water, Wooden Boats</span><span class="text-[.88rem] text-muted">Photo essay · 15 images</span></span></a></div>
<div class="md:col-span-2"><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#525872] uppercase">Diagonal clip-path wipe</span>
<a href="#" class="group block rounded-2xl text-ink no-underline focus-visible:outline-3 focus-visible:outline-offset-5 focus-visible:outline-indigo"><span class="relative isolate block overflow-hidden rounded-2xl bg-[#d5d9e3] aspect-[4/3] md:aspect-[21/9] "><img class="absolute inset-0 size-full object-cover transition-[filter] duration-600 " src="https://images.unsplash.com/photo-1513635269975-59663e0ac1ad?auto=format&fit=crop&w=1600&h=686&q=70" alt="Aerial view of London with Tower Bridge crossing the Thames" width="1600" height="686">
  <span class="absolute inset-0 z-1 flex flex-col items-start justify-center gap-2 bg-[rgba(49,46,129,.94)] py-0 pr-[22%] pl-[clamp(20px,5vw,48px)] leading-[1.4] text-white md:pr-[48%] [clip-path:polygon(0_0,0_0,0_100%,0_100%)] transition-[clip-path] duration-700 ease-[cubic-bezier(.3,.7,.2,1)] max-md:group-hover:[clip-path:polygon(0_0,92%_0,80%_100%,0_100%)] max-md:group-focus-visible:[clip-path:polygon(0_0,92%_0,80%_100%,0_100%)] md:group-hover:[clip-path:polygon(0_0,64%_0,52%_100%,0_100%)] md:group-focus-visible:[clip-path:polygon(0_0,64%_0,52%_100%,0_100%)] max-md:touch:[clip-path:polygon(0_0,92%_0,80%_100%,0_100%)]! md:touch:[clip-path:polygon(0_0,64%_0,52%_100%,0_100%)]! motion-reduce:transition-none"><i class="text-[.72rem] font-bold tracking-[.14em] text-[#c7d2fe] uppercase not-italic">City guide</i><b class="text-[clamp(1.15rem,2.4vw,1.6rem)] leading-[1.15]">14 routes, 3 to 9 km</b><span class="text-[.92rem] text-[#e0e7ff]">Step-free options and cafés marked on every map.</span></span></span>
  <span class="grid gap-0.5 px-0.5 pt-3.5 leading-[1.4]"><span class="text-[1.05rem] font-bold underline decoration-transparent decoration-2 underline-offset-4 transition-[text-decoration-color] duration-300 group-hover:decoration-indigo group-focus-visible:decoration-indigo">London in Fourteen Walks</span><span class="text-[.88rem] text-muted">Guide · updated October 2026</span></span></a></div>
</div>
CSS
/* touch: screens without hover get the finished state */
@custom-variant touch (@media (hover: none));
@theme {
  --color-indigo: #4338ca;
  --color-ink: #161a2b;
  --color-muted: #4a5068;
}

About this set

Six image treatments that change on hover, shown on a photo magazine. Grayscale to colour turns a team row of three portraits from black and white to full colour. Duotone to full colour starts as an indigo and pink duotone, made by multiplying a light colour and lightening a dark colour over a grey photo, and fades to the original. Blur to sharp brings a soft, desaturated photo into focus. Sepia to colour warms an old-print look back to the real colours. Circle mask reveal shows a colour porthole in a dimmed grey photo and opens it to the whole frame with an animated clip-path circle. Diagonal clip-path wipe slides a slanted indigo panel with guide details across a wide banner. Filters and opacity are not motion, so they keep their fades under reduced motion, while the two clip-path reveals switch instantly instead. On touch screens every photo shows its finished state straight away, so nobody is left with a blurred or grey image they cannot change.

What’s included

  • Grayscale, duotone, blur and sepia filters that clear on hover
  • Duotone built from mix-blend-mode multiply and lighten layers
  • Circle and diagonal reveals with animated clip-path
  • Finished state shown on touch screens
  • Clip-path reveals switch instantly under reduced motion

Accessibility

Every tile is a link named by a descriptive alt text and its visible title; the duplicate colour photo in the circle reveal has an empty alt. Keyboard focus shows a 3px outline and triggers the same change as hover. The filter fades are not motion and stay; the clip-path reveals stop animating under prefers-reduced-motion.

Customise it

Change --fx-accent, --fx-radius and --fx-speed on .fx, --fx-light and --fx-dark on .fx-duo for the duotone, and the filter values in each variant. In Bootstrap the same rules apply to .figure and .ratio markup; in Tailwind edit the grayscale-, sepia-, blur- and clip-path utilities.