Open demo

CSS code

HTML
<div><span class="lbl">Renovation before and after cards</span>
<section aria-labelledby="rn-title">
  <div class="rn-head"><div><p class="rn-kicker">Oakline Interiors</p><h2 id="rn-title">Recent renovations</h2></div><p>Drag each photo to compare</p></div>
  <ul class="rn-grid" role="list">
    <li><article class="rn-card">
      <div class="ic" data-compare>
        <img src="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" loading="lazy" alt="After: a white kitchen with black pendant lights, steel appliances and bar stools at an island">
        <div class="ic-before"><img src="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" loading="lazy" alt="Before: the same kitchen, dim and yellowed"></div>
        <span class="ic-tag ic-tag-b" aria-hidden="true">Before</span><span class="ic-tag ic-tag-a" aria-hidden="true">After</span>
        <input class="ic-range" type="range" min="0" max="100" value="50" aria-label="Compare the kitchen before and after" aria-valuetext="50% after" data-compare-range>
        <span class="ic-handle" aria-hidden="true"><span class="ic-knob"><svg viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span></span>
      </div>
      <div class="rn-body"><h3>Galley kitchen refit</h3><p class="rn-where">Hawthorn Street, Portland</p>
        <dl class="rn-stats"><div><dt>Budget</dt><dd>$24,800</dd></div><div><dt>Time</dt><dd>5 weeks</dd></div></dl></div>
    </article></li>
    <li><article class="rn-card">
      <div class="ic" data-compare>
        <img src="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" loading="lazy" alt="After: a white bathroom with a walk-in glass shower and a long vanity">
        <div class="ic-before"><img src="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" loading="lazy" alt="Before: the same bathroom, dingy and discoloured"></div>
        <span class="ic-tag ic-tag-b" aria-hidden="true">Before</span><span class="ic-tag ic-tag-a" aria-hidden="true">After</span>
        <input class="ic-range" type="range" min="0" max="100" value="50" aria-label="Compare the bathroom before and after" aria-valuetext="50% after" data-compare-range>
        <span class="ic-handle" aria-hidden="true"><span class="ic-knob"><svg viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span></span>
      </div>
      <div class="rn-body"><h3>Walk-in shower bathroom</h3><p class="rn-where">Alder Court, Beaverton</p>
        <dl class="rn-stats"><div><dt>Budget</dt><dd>$13,500</dd></div><div><dt>Time</dt><dd>3 weeks</dd></div></dl></div>
    </article></li>
    <li><article class="rn-card">
      <div class="ic" data-compare>
        <img src="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" loading="lazy" alt="After: a living room with a mustard armchair, a brass floor lamp and a framed print on a pale wall">
        <div class="ic-before"><img src="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" loading="lazy" alt="Before: the same living room, faded and brownish"></div>
        <span class="ic-tag ic-tag-b" aria-hidden="true">Before</span><span class="ic-tag ic-tag-a" aria-hidden="true">After</span>
        <input class="ic-range" type="range" min="0" max="100" value="50" aria-label="Compare the living room before and after" aria-valuetext="50% after" data-compare-range>
        <span class="ic-handle" aria-hidden="true"><span class="ic-knob"><svg viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span></span>
      </div>
      <div class="rn-body"><h3>Reading corner makeover</h3><p class="rn-where">Larch Avenue, Lake Oswego</p>
        <dl class="rn-stats"><div><dt>Budget</dt><dd>$6,900</dd></div><div><dt>Time</dt><dd>9 days</dd></div></dl></div>
    </article></li>
  </ul>
</section></div>

<div><span class="lbl">Product retouch showcase</span>
<article class="pr" aria-labelledby="pr-title">
  <div class="ic" data-compare>
    <img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70" srcset="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=480&h=480&q=70 480w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70 720w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=1000&h=1000&q=70 1000w" sizes="(min-width: 1120px) 540px, (min-width: 768px) 50vw, 100vw" width="1000" height="1000" loading="lazy" alt="Retouched: a red knit running shoe on a red background, with clean, vivid colour">
    <div class="ic-before"><img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70" srcset="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=480&h=480&q=70 480w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70 720w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=1000&h=1000&q=70 1000w" sizes="(min-width: 1120px) 540px, (min-width: 768px) 50vw, 100vw" width="1000" height="1000" loading="lazy" alt="Raw: the same shoe shot, muddy and underexposed"></div>
    <span class="ic-tag ic-tag-b" aria-hidden="true">Raw</span><span class="ic-tag ic-tag-a" aria-hidden="true">Retouched</span>
    <input class="ic-range" type="range" min="0" max="100" value="50" aria-label="Compare the raw and retouched shoe photo" aria-valuetext="50% after" data-compare-range>
    <span class="ic-handle" aria-hidden="true"><span class="ic-knob"><svg viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span></span>
  </div>
  <div class="pr-body">
    <p class="pr-kicker">Pixelcraft Studio</p>
    <h3 id="pr-title">E-commerce product retouching</h3>
    <p class="pr-lead">Colour matched to the real product, so returns for “it looked different online” go down.</p>
    <ul class="pr-list"><li>Colour match against a physical sample</li><li>Dust, lint and crease clean-up</li><li>Background extension to any ratio</li></ul>
    <div class="pr-price"><div><small>From</small><strong>$4.50 per image</strong></div><a class="pr-cta" href="#pricing">See pricing</a></div>
  </div>
</article></div>
CSS
/* Compare stage (same technique as the classic slider): the range value drives --v. */
.ic{--v:50;--thumb:40px;--x:calc(var(--thumb) / 2 + (100% - var(--thumb)) * var(--v) / 100);--ic-focus:#1d4ed8;
  position:relative;display:block;aspect-ratio:4/3;overflow:hidden;background:#d8d3ca;isolation:isolate;user-select:none;-webkit-user-select:none}
.ic img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;pointer-events:none}
.ic-before{position:absolute;inset:0;clip-path:inset(0 calc(100% - var(--x)) 0 0)}
.ic-before img{filter:var(--ic-before,brightness(.74) contrast(.8) saturate(.55) sepia(.7))}
.ic-tag{position:absolute;top:12px;padding:4px 10px;border-radius:999px;background:rgba(15,17,21,.78);color:#fff;
  font-size:.68rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;pointer-events:none;transition:opacity .2s}
.ic-tag-b{left:12px;opacity:clamp(0,calc((var(--v) - 18) / 8),1)}
.ic-tag-a{right:12px;opacity:clamp(0,calc((82 - var(--v)) / 8),1)}
.ic-range{position:absolute;inset:0;z-index:2;width:100%;height:100%;margin:0;opacity:0;cursor:ew-resize;-webkit-appearance:none;appearance:none;background:none}
.ic-range::-webkit-slider-runnable-track{height:100%}
.ic-range::-webkit-slider-thumb{-webkit-appearance:none;width:var(--thumb);height:100%}
.ic-range::-moz-range-thumb{width:var(--thumb);height:100%;border:0}
.ic-handle{position:absolute;top:0;bottom:0;left:var(--x);width:0;pointer-events:none;z-index:1}
.ic-handle::before{content:"";position:absolute;top:0;bottom:0;left:-1px;width:2px;background:#fff;box-shadow:0 0 8px rgba(0,0,0,.35)}
.ic-knob{position:absolute;top:50%;left:0;display:grid;place-items:center;width:38px;height:38px;translate:-50% -50%;border-radius:50%;background:#fff;color:#16181d;box-shadow:0 3px 12px rgba(0,0,0,.3)}
.ic-knob svg{width:18px;height:18px}
.ic-range:focus-visible ~ .ic-handle .ic-knob{outline:3px solid var(--ic-focus);outline-offset:3px;box-shadow:0 0 0 3px #fff}

/* 1. Renovation cards */
.rn-head{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:6px 24px;margin-bottom:22px}
.rn-kicker{font-size:.75rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:#8a3a14}
.rn-head h2{margin-top:4px;font-size:1.75rem;line-height:1.15;letter-spacing:-.02em}
.rn-head p:last-child{font-size:.9rem;color:#5f5a52}
.rn-grid{list-style:none;display:grid;grid-template-columns:1fr;gap:22px}
@media (min-width:576px){.rn-grid{grid-template-columns:repeat(2,1fr)}}
@media (min-width:992px){.rn-grid{grid-template-columns:repeat(3,1fr)}}
.rn-card{height:100%;overflow:hidden;border-radius:18px;background:#fff;box-shadow:0 1px 2px rgba(22,24,29,.06),0 14px 34px -18px rgba(22,24,29,.3)}
.rn-body{padding:16px 18px 18px}
.rn-body h3{font-size:1.05rem;font-weight:650;letter-spacing:-.01em}
.rn-where{margin-top:3px;font-size:.84rem;color:#5f5a52}
.rn-stats{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:14px;padding-top:14px;border-top:1px solid #ebe7e0}
.rn-stats dt{font-size:.7rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:#5f5a52}
.rn-stats dd{margin-top:2px;font-size:.95rem;font-weight:650}

/* 2. Product retouch showcase */
.pr{display:grid;overflow:hidden;border-radius:22px;background:#16181d;color:#f4f2ee}
@media (min-width:768px){.pr{grid-template-columns:1fr 1fr}}
.pr .ic{aspect-ratio:1;--ic-before:brightness(.8) contrast(.86) hue-rotate(-10deg) saturate(.55)}
.pr-body{display:flex;flex-direction:column;justify-content:center;gap:14px;padding:30px clamp(22px,4vw,44px)}
.pr-kicker{font-size:.75rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:#f6a07a}
.pr-body h3{font-size:1.65rem;line-height:1.15;letter-spacing:-.02em}
.pr-lead{color:#c9c6bf;line-height:1.55}
.pr-list{list-style:none;display:grid;gap:8px;font-size:.92rem}
.pr-list li{display:flex;gap:10px;align-items:baseline}
.pr-list li::before{content:"";flex:none;width:8px;height:8px;border-radius:50%;background:#f6a07a;translate:0 -1px}
.pr-price{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px;margin-top:6px;padding-top:16px;border-top:1px solid #33363d}
.pr-price strong{font-size:1.4rem}
.pr-price small{display:block;font-size:.8rem;color:#b5b2ab}
.pr-cta{display:inline-block;padding:11px 20px;border-radius:999px;background:#f4f2ee;color:#16181d;font-size:.9rem;font-weight:700;text-decoration:none}
.pr-cta:hover{background:#fff}
.pr-cta:focus-visible{outline:3px solid #f6a07a;outline-offset:3px}
@media (prefers-reduced-motion:reduce){.ic-tag{transition:none}}
JavaScript
// Before/after slider: the range input is the control. This mirrors its value into --v
// (which moves the divider and clip) and gives screen readers a readable value.
document.querySelectorAll('[data-compare]').forEach((root) => {
  const range = root.querySelector('[data-compare-range]');
  if (!range) return;
  const sync = () => {
    root.style.setProperty('--v', range.value);
    range.setAttribute('aria-valuetext', `${100 - range.value}% after`);
  };
  range.addEventListener('input', sync);
  sync();
});

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Renovation before and after cards</span>
<section aria-labelledby="rnb-title">
  <div class="d-flex flex-wrap align-items-end justify-content-between column-gap-4 row-gap-1 mb-4"><div><p class="rn-kicker mb-0">Oakline Interiors</p><h2 id="rnb-title" class="rn-title fw-bold mt-1 mb-0">Recent renovations</h2></div><p class="rn-note mb-0">Drag each photo to compare</p></div>
  <div class="row row-cols-1 row-cols-sm-2 row-cols-lg-3 g-4">
    <div class="col"><article class="card rn-card h-100 border-0">
      <div class="ic ratio ratio-4x3" data-compare>
        <img src="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" loading="lazy" alt="After: a white kitchen with black pendant lights, steel appliances and bar stools at an island">
        <div class="ic-before"><img src="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" class="w-100 h-100" loading="lazy" alt="Before: the same kitchen, dim and yellowed"></div>
        <div class="pe-none"><span class="badge rounded-pill position-absolute ic-tag-b" aria-hidden="true">Before</span><span class="badge rounded-pill position-absolute ic-tag-a" aria-hidden="true">After</span></div>
        <input class="form-range" type="range" min="0" max="100" value="50" aria-label="Compare the kitchen before and after" aria-valuetext="50% after" data-compare-range>
        <span class="ic-handle" aria-hidden="true"><span class="ic-knob"><svg viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span></span>
      </div>
      <div class="card-body rn-body"><h3 class="card-title">Galley kitchen refit</h3><p class="rn-where mb-0">Hawthorn Street, Portland</p>
        <dl class="row g-2 rn-stats mb-0"><div class="col-6"><dt>Budget</dt><dd class="mb-0">$24,800</dd></div><div class="col-6"><dt>Time</dt><dd class="mb-0">5 weeks</dd></div></dl></div>
    </article></div>
    <div class="col"><article class="card rn-card h-100 border-0">
      <div class="ic ratio ratio-4x3" data-compare>
        <img src="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" loading="lazy" alt="After: a white bathroom with a walk-in glass shower and a long vanity">
        <div class="ic-before"><img src="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" class="w-100 h-100" loading="lazy" alt="Before: the same bathroom, dingy and discoloured"></div>
        <div class="pe-none"><span class="badge rounded-pill position-absolute ic-tag-b" aria-hidden="true">Before</span><span class="badge rounded-pill position-absolute ic-tag-a" aria-hidden="true">After</span></div>
        <input class="form-range" type="range" min="0" max="100" value="50" aria-label="Compare the bathroom before and after" aria-valuetext="50% after" data-compare-range>
        <span class="ic-handle" aria-hidden="true"><span class="ic-knob"><svg viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span></span>
      </div>
      <div class="card-body rn-body"><h3 class="card-title">Walk-in shower bathroom</h3><p class="rn-where mb-0">Alder Court, Beaverton</p>
        <dl class="row g-2 rn-stats mb-0"><div class="col-6"><dt>Budget</dt><dd class="mb-0">$13,500</dd></div><div class="col-6"><dt>Time</dt><dd class="mb-0">3 weeks</dd></div></dl></div>
    </article></div>
    <div class="col"><article class="card rn-card h-100 border-0">
      <div class="ic ratio ratio-4x3" data-compare>
        <img src="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" loading="lazy" alt="After: a living room with a mustard armchair, a brass floor lamp and a framed print on a pale wall">
        <div class="ic-before"><img src="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" class="w-100 h-100" loading="lazy" alt="Before: the same living room, faded and brownish"></div>
        <div class="pe-none"><span class="badge rounded-pill position-absolute ic-tag-b" aria-hidden="true">Before</span><span class="badge rounded-pill position-absolute ic-tag-a" aria-hidden="true">After</span></div>
        <input class="form-range" type="range" min="0" max="100" value="50" aria-label="Compare the living room before and after" aria-valuetext="50% after" data-compare-range>
        <span class="ic-handle" aria-hidden="true"><span class="ic-knob"><svg viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span></span>
      </div>
      <div class="card-body rn-body"><h3 class="card-title">Reading corner makeover</h3><p class="rn-where mb-0">Larch Avenue, Lake Oswego</p>
        <dl class="row g-2 rn-stats mb-0"><div class="col-6"><dt>Budget</dt><dd class="mb-0">$6,900</dd></div><div class="col-6"><dt>Time</dt><dd class="mb-0">9 days</dd></div></dl></div>
    </article></div>
  </div>
</section></div>

<div><span class="lbl">Product retouch showcase</span>
<article class="card pr text-bg-dark border-0" aria-labelledby="prb-title">
  <div class="row g-0">
  <div class="col-md-6"><div class="ic ratio ratio-1x1" data-compare>
    <img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70" srcset="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=480&h=480&q=70 480w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70 720w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=1000&h=1000&q=70 1000w" sizes="(min-width: 1120px) 540px, (min-width: 768px) 50vw, 100vw" width="1000" height="1000" loading="lazy" alt="Retouched: a red knit running shoe on a red background, with clean, vivid colour">
    <div class="ic-before"><img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70" srcset="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=480&h=480&q=70 480w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70 720w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=1000&h=1000&q=70 1000w" sizes="(min-width: 1120px) 540px, (min-width: 768px) 50vw, 100vw" width="1000" height="1000" class="w-100 h-100" loading="lazy" alt="Raw: the same shoe shot, muddy and underexposed"></div>
    <div class="pe-none"><span class="badge rounded-pill position-absolute ic-tag-b" aria-hidden="true">Raw</span><span class="badge rounded-pill position-absolute ic-tag-a" aria-hidden="true">Retouched</span></div>
    <input class="form-range" type="range" min="0" max="100" value="50" aria-label="Compare the raw and retouched shoe photo" aria-valuetext="50% after" data-compare-range>
    <span class="ic-handle" aria-hidden="true"><span class="ic-knob"><svg viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span></span>
  </div></div>
  <div class="col-md-6 d-flex"><div class="card-body pr-body d-flex flex-column justify-content-center">
    <p class="pr-kicker mb-0">Pixelcraft Studio</p>
    <h3 id="prb-title" class="pr-title fw-bold mb-0">E-commerce product retouching</h3>
    <p class="pr-lead mb-0">Colour matched to the real product, so returns for “it looked different online” go down.</p>
    <ul class="pr-list list-unstyled mb-0"><li>Colour match against a physical sample</li><li>Dust, lint and crease clean-up</li><li>Background extension to any ratio</li></ul>
    <div class="pr-price d-flex flex-wrap align-items-center justify-content-between gap-3"><div><small class="d-block">From</small><strong>$4.50 per image</strong></div><a class="btn btn-light rounded-pill" href="#pricing">See pricing</a></div>
  </div></div>
  </div>
</article></div>
CSS
/* Compare stage on .ratio with .form-range as the control: the range value drives --v. */
.ic{--v:50;--thumb:40px;--x:calc(var(--thumb) / 2 + (100% - var(--thumb)) * var(--v) / 100);--ic-focus:#1d4ed8;
  overflow:hidden;background:#d8d3ca;isolation:isolate;user-select:none;-webkit-user-select:none}
.ic img{object-fit:cover;pointer-events:none}
.ic-before{clip-path:inset(0 calc(100% - var(--x)) 0 0)}
.ic-before img{filter:var(--ic-before,brightness(.74) contrast(.8) saturate(.55) sepia(.7))}
.ic .badge{top:12px;padding:4px 10px;background:rgba(15,17,21,.78);font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;transition:opacity .2s}
.ic .ic-tag-b{left:12px;opacity:clamp(0,calc((var(--v) - 18) / 8),1)}
.ic .ic-tag-a{right:12px;opacity:clamp(0,calc((82 - var(--v)) / 8),1)}
.ic .form-range{z-index:2;opacity:0;cursor:ew-resize}
.ic .form-range::-webkit-slider-runnable-track{height:100%}
.ic .form-range::-webkit-slider-thumb{width:var(--thumb);height:100%;margin-top:0}
.ic .form-range::-moz-range-thumb{width:var(--thumb);height:100%}
.ic-handle{left:var(--x);width:0;pointer-events:none;z-index:1}
.ic-handle::before{content:"";position:absolute;top:0;bottom:0;left:-1px;width:2px;background:#fff;box-shadow:0 0 8px rgba(0,0,0,.35)}
.ic-knob{position:absolute;top:50%;left:0;display:grid;place-items:center;width:38px;height:38px;translate:-50% -50%;border-radius:50%;background:#fff;color:#16181d;box-shadow:0 3px 12px rgba(0,0,0,.3)}
.ic-knob svg{width:18px;height:18px}
.ic .form-range:focus-visible ~ .ic-handle .ic-knob{outline:3px solid var(--ic-focus);outline-offset:3px;box-shadow:0 0 0 3px #fff}

/* 1. Renovation cards (.card in .row-cols-*) */
.rn-kicker{font-size:.75rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:#8a3a14}
.rn-title{font-size:1.75rem;line-height:1.15;letter-spacing:-.02em}
.rn-note{font-size:.9rem;color:#5f5a52}
.rn-card{border-radius:18px;overflow:hidden;box-shadow:0 1px 2px rgba(22,24,29,.06),0 14px 34px -18px rgba(22,24,29,.3)}
.rn-body{padding:16px 18px 18px}
.rn-body .card-title{margin:0;font-size:1.05rem;font-weight:650;letter-spacing:-.01em}
.rn-where{margin-top:3px;font-size:.84rem;color:#5f5a52}
.rn-stats{margin-top:14px;padding-top:6px;border-top:1px solid #ebe7e0}
.rn-stats dt{font-size:.7rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:#5f5a52}
.rn-stats dd{margin-top:2px;font-size:.95rem;font-weight:650}

/* 2. Product retouch showcase (.card.text-bg-dark with a .row.g-0) */
.pr{border-radius:22px;overflow:hidden;background:#16181d!important;color:#f4f2ee!important}
.pr .ic{--ic-before:brightness(.8) contrast(.86) hue-rotate(-10deg) saturate(.55)}
.pr-body{gap:14px;padding:30px clamp(22px,4vw,44px)}
.pr-kicker{font-size:.75rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:#f6a07a}
.pr-title{font-size:1.65rem;line-height:1.15;letter-spacing:-.02em}
.pr-lead{color:#c9c6bf;line-height:1.55}
.pr-list{display:grid;gap:8px;font-size:.92rem}
.pr-list li{display:flex;gap:10px;align-items:baseline}
.pr-list li::before{content:"";flex:none;width:8px;height:8px;border-radius:50%;background:#f6a07a;translate:0 -1px}
.pr-price{margin-top:6px;padding-top:16px;border-top:1px solid #33363d}
.pr-price strong{font-size:1.4rem}
.pr-price small{font-size:.8rem;color:#b5b2ab}
.pr .btn{--bs-btn-padding-x:20px;--bs-btn-padding-y:11px;--bs-btn-font-size:.9rem;--bs-btn-font-weight:700;--bs-btn-bg:#f4f2ee;--bs-btn-border-color:#f4f2ee;line-height:normal}
.pr .btn:focus-visible{outline:3px solid #f6a07a;outline-offset:3px;box-shadow:none}
@media (prefers-reduced-motion:reduce){.ic .badge{transition:none}}
JavaScript
// Before/after slider: the range input is the control. This mirrors its value into --v
// (which moves the divider and clip) and gives screen readers a readable value.
document.querySelectorAll('[data-compare]').forEach((root) => {
  const range = root.querySelector('[data-compare-range]');
  if (!range) return;
  const sync = () => {
    root.style.setProperty('--v', range.value);
    range.setAttribute('aria-valuetext', `${100 - range.value}% after`);
  };
  range.addEventListener('input', sync);
  sync();
});

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#5f5a52] uppercase">Renovation before and after cards</span>
<section aria-labelledby="rnt-title">
  <div class="mb-[22px] flex flex-wrap items-end justify-between gap-x-6 gap-y-1.5"><div><p class="text-xs font-bold tracking-[.14em] text-[#8a3a14] uppercase">Oakline Interiors</p><h2 id="rnt-title" class="mt-1 text-[1.75rem] leading-[1.15] font-bold tracking-[-.02em]">Recent renovations</h2></div><p class="text-[.9rem] text-[#5f5a52]">Drag each photo to compare</p></div>
  <ul class="grid grid-cols-1 gap-[22px] min-[576px]:grid-cols-2 min-[992px]:grid-cols-3" role="list">
    <li><article class="h-full overflow-hidden rounded-[18px] bg-white shadow-[0_1px_2px_rgba(22,24,29,.06),0_14px_34px_-18px_rgba(22,24,29,.3)]">
      <div class="compare group relative isolate block aspect-[4/3] overflow-hidden bg-[#d8d3ca] select-none [--thumb:40px] [--v:50]" data-compare>
        <img src="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" class="pointer-events-none absolute inset-0 block size-full object-cover" loading="lazy" alt="After: a white kitchen with black pendant lights, steel appliances and bar stools at an island">
        <div class="clip-before absolute inset-0"><img src="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1484154218962-a197022b5858?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" class="pointer-events-none absolute inset-0 block size-full object-cover brightness-74 contrast-80 saturate-55 sepia-70" loading="lazy" alt="Before: the same kitchen, dim and yellowed"></div>
        <span class="pointer-events-none absolute top-3 rounded-full bg-[rgba(15,17,21,.78)] px-2.5 py-1 text-[.68rem] font-bold tracking-[.08em] text-white uppercase transition-opacity duration-200 motion-reduce:transition-none left-3 opacity-[clamp(0,calc((var(--v)_-_18)/8),1)]" aria-hidden="true">Before</span><span class="pointer-events-none absolute top-3 rounded-full bg-[rgba(15,17,21,.78)] px-2.5 py-1 text-[.68rem] font-bold tracking-[.08em] text-white uppercase transition-opacity duration-200 motion-reduce:transition-none right-3 opacity-[clamp(0,calc((82_-_var(--v))/8),1)]" aria-hidden="true">After</span>
        <input class="compare-range peer absolute inset-0 z-2 m-0 size-full cursor-ew-resize opacity-0" type="range" min="0" max="100" value="50" aria-label="Compare the kitchen before and after" aria-valuetext="50% after" data-compare-range>
        <span class="pointer-events-none absolute inset-y-0 left-(--x) z-1 w-0.5 -translate-x-1/2 bg-white shadow-[0_0_8px_rgba(0,0,0,.35)]" data-handle aria-hidden="true"></span>
        <span class="pointer-events-none absolute top-1/2 left-(--x) z-1 grid size-[38px] -translate-1/2 place-items-center rounded-full bg-white text-[#16181d] shadow-[0_3px_12px_rgba(0,0,0,.3)] peer-focus-visible:shadow-[0_0_0_3px_#fff] peer-focus-visible:outline-3 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-[#1d4ed8]" aria-hidden="true"><svg class="size-[18px]" viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
      </div>
      <div class="px-[18px] pt-4 pb-[18px]"><h3 class="text-[1.05rem] font-semibold tracking-[-.01em]">Galley kitchen refit</h3><p class="mt-[3px] text-[.84rem] text-[#5f5a52]">Hawthorn Street, Portland</p>
        <dl class="mt-3.5 grid grid-cols-2 gap-2.5 border-t border-[#ebe7e0] pt-3.5"><div><dt class="text-[.7rem] font-bold tracking-[.1em] text-[#5f5a52] uppercase">Budget</dt><dd class="mt-0.5 text-[.95rem] font-semibold">$24,800</dd></div><div><dt class="text-[.7rem] font-bold tracking-[.1em] text-[#5f5a52] uppercase">Time</dt><dd class="mt-0.5 text-[.95rem] font-semibold">5 weeks</dd></div></dl></div>
    </article></li>
    <li><article class="h-full overflow-hidden rounded-[18px] bg-white shadow-[0_1px_2px_rgba(22,24,29,.06),0_14px_34px_-18px_rgba(22,24,29,.3)]">
      <div class="compare group relative isolate block aspect-[4/3] overflow-hidden bg-[#d8d3ca] select-none [--thumb:40px] [--v:50]" data-compare>
        <img src="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" class="pointer-events-none absolute inset-0 block size-full object-cover" loading="lazy" alt="After: a white bathroom with a walk-in glass shower and a long vanity">
        <div class="clip-before absolute inset-0"><img src="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1584622650111-993a426fbf0a?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" class="pointer-events-none absolute inset-0 block size-full object-cover brightness-74 contrast-80 saturate-55 sepia-70" loading="lazy" alt="Before: the same bathroom, dingy and discoloured"></div>
        <span class="pointer-events-none absolute top-3 rounded-full bg-[rgba(15,17,21,.78)] px-2.5 py-1 text-[.68rem] font-bold tracking-[.08em] text-white uppercase transition-opacity duration-200 motion-reduce:transition-none left-3 opacity-[clamp(0,calc((var(--v)_-_18)/8),1)]" aria-hidden="true">Before</span><span class="pointer-events-none absolute top-3 rounded-full bg-[rgba(15,17,21,.78)] px-2.5 py-1 text-[.68rem] font-bold tracking-[.08em] text-white uppercase transition-opacity duration-200 motion-reduce:transition-none right-3 opacity-[clamp(0,calc((82_-_var(--v))/8),1)]" aria-hidden="true">After</span>
        <input class="compare-range peer absolute inset-0 z-2 m-0 size-full cursor-ew-resize opacity-0" type="range" min="0" max="100" value="50" aria-label="Compare the bathroom before and after" aria-valuetext="50% after" data-compare-range>
        <span class="pointer-events-none absolute inset-y-0 left-(--x) z-1 w-0.5 -translate-x-1/2 bg-white shadow-[0_0_8px_rgba(0,0,0,.35)]" data-handle aria-hidden="true"></span>
        <span class="pointer-events-none absolute top-1/2 left-(--x) z-1 grid size-[38px] -translate-1/2 place-items-center rounded-full bg-white text-[#16181d] shadow-[0_3px_12px_rgba(0,0,0,.3)] peer-focus-visible:shadow-[0_0_0_3px_#fff] peer-focus-visible:outline-3 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-[#1d4ed8]" aria-hidden="true"><svg class="size-[18px]" viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
      </div>
      <div class="px-[18px] pt-4 pb-[18px]"><h3 class="text-[1.05rem] font-semibold tracking-[-.01em]">Walk-in shower bathroom</h3><p class="mt-[3px] text-[.84rem] text-[#5f5a52]">Alder Court, Beaverton</p>
        <dl class="mt-3.5 grid grid-cols-2 gap-2.5 border-t border-[#ebe7e0] pt-3.5"><div><dt class="text-[.7rem] font-bold tracking-[.1em] text-[#5f5a52] uppercase">Budget</dt><dd class="mt-0.5 text-[.95rem] font-semibold">$13,500</dd></div><div><dt class="text-[.7rem] font-bold tracking-[.1em] text-[#5f5a52] uppercase">Time</dt><dd class="mt-0.5 text-[.95rem] font-semibold">3 weeks</dd></div></dl></div>
    </article></li>
    <li><article class="h-full overflow-hidden rounded-[18px] bg-white shadow-[0_1px_2px_rgba(22,24,29,.06),0_14px_34px_-18px_rgba(22,24,29,.3)]">
      <div class="compare group relative isolate block aspect-[4/3] overflow-hidden bg-[#d8d3ca] select-none [--thumb:40px] [--v:50]" data-compare>
        <img src="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" class="pointer-events-none absolute inset-0 block size-full object-cover" loading="lazy" alt="After: a living room with a mustard armchair, a brass floor lamp and a framed print on a pale wall">
        <div class="clip-before absolute inset-0"><img src="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70" srcset="https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=400&h=300&q=70 400w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=640&h=480&q=70 640w, https://images.unsplash.com/photo-1586023492125-27b2c045efd7?auto=format&fit=crop&w=880&h=660&q=70 880w" sizes="(min-width: 992px) 345px, (min-width: 576px) 50vw, 100vw" width="880" height="660" class="pointer-events-none absolute inset-0 block size-full object-cover brightness-74 contrast-80 saturate-55 sepia-70" loading="lazy" alt="Before: the same living room, faded and brownish"></div>
        <span class="pointer-events-none absolute top-3 rounded-full bg-[rgba(15,17,21,.78)] px-2.5 py-1 text-[.68rem] font-bold tracking-[.08em] text-white uppercase transition-opacity duration-200 motion-reduce:transition-none left-3 opacity-[clamp(0,calc((var(--v)_-_18)/8),1)]" aria-hidden="true">Before</span><span class="pointer-events-none absolute top-3 rounded-full bg-[rgba(15,17,21,.78)] px-2.5 py-1 text-[.68rem] font-bold tracking-[.08em] text-white uppercase transition-opacity duration-200 motion-reduce:transition-none right-3 opacity-[clamp(0,calc((82_-_var(--v))/8),1)]" aria-hidden="true">After</span>
        <input class="compare-range peer absolute inset-0 z-2 m-0 size-full cursor-ew-resize opacity-0" type="range" min="0" max="100" value="50" aria-label="Compare the living room before and after" aria-valuetext="50% after" data-compare-range>
        <span class="pointer-events-none absolute inset-y-0 left-(--x) z-1 w-0.5 -translate-x-1/2 bg-white shadow-[0_0_8px_rgba(0,0,0,.35)]" data-handle aria-hidden="true"></span>
        <span class="pointer-events-none absolute top-1/2 left-(--x) z-1 grid size-[38px] -translate-1/2 place-items-center rounded-full bg-white text-[#16181d] shadow-[0_3px_12px_rgba(0,0,0,.3)] peer-focus-visible:shadow-[0_0_0_3px_#fff] peer-focus-visible:outline-3 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-[#1d4ed8]" aria-hidden="true"><svg class="size-[18px]" viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
      </div>
      <div class="px-[18px] pt-4 pb-[18px]"><h3 class="text-[1.05rem] font-semibold tracking-[-.01em]">Reading corner makeover</h3><p class="mt-[3px] text-[.84rem] text-[#5f5a52]">Larch Avenue, Lake Oswego</p>
        <dl class="mt-3.5 grid grid-cols-2 gap-2.5 border-t border-[#ebe7e0] pt-3.5"><div><dt class="text-[.7rem] font-bold tracking-[.1em] text-[#5f5a52] uppercase">Budget</dt><dd class="mt-0.5 text-[.95rem] font-semibold">$6,900</dd></div><div><dt class="text-[.7rem] font-bold tracking-[.1em] text-[#5f5a52] uppercase">Time</dt><dd class="mt-0.5 text-[.95rem] font-semibold">9 days</dd></div></dl></div>
    </article></li>
  </ul>
</section></div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#5f5a52] uppercase">Product retouch showcase</span>
<article class="grid overflow-hidden rounded-[22px] bg-[#16181d] text-[#f4f2ee] min-[768px]:grid-cols-2" aria-labelledby="prt-title">
  <div class="compare group relative isolate block aspect-square overflow-hidden bg-[#d8d3ca] select-none [--thumb:40px] [--v:50]" data-compare>
        <img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70" srcset="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=480&h=480&q=70 480w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70 720w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=1000&h=1000&q=70 1000w" sizes="(min-width: 1120px) 540px, (min-width: 768px) 50vw, 100vw" width="1000" height="1000" class="pointer-events-none absolute inset-0 block size-full object-cover" loading="lazy" alt="Retouched: a red knit running shoe on a red background, with clean, vivid colour">
        <div class="clip-before absolute inset-0"><img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70" srcset="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=480&h=480&q=70 480w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=720&h=720&q=70 720w, https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=1000&h=1000&q=70 1000w" sizes="(min-width: 1120px) 540px, (min-width: 768px) 50vw, 100vw" width="1000" height="1000" class="pointer-events-none absolute inset-0 block size-full object-cover brightness-80 contrast-86 saturate-55 -hue-rotate-10" loading="lazy" alt="Raw: the same shoe shot, muddy and underexposed"></div>
        <span class="pointer-events-none absolute top-3 rounded-full bg-[rgba(15,17,21,.78)] px-2.5 py-1 text-[.68rem] font-bold tracking-[.08em] text-white uppercase transition-opacity duration-200 motion-reduce:transition-none left-3 opacity-[clamp(0,calc((var(--v)_-_18)/8),1)]" aria-hidden="true">Raw</span><span class="pointer-events-none absolute top-3 rounded-full bg-[rgba(15,17,21,.78)] px-2.5 py-1 text-[.68rem] font-bold tracking-[.08em] text-white uppercase transition-opacity duration-200 motion-reduce:transition-none right-3 opacity-[clamp(0,calc((82_-_var(--v))/8),1)]" aria-hidden="true">Retouched</span>
        <input class="compare-range peer absolute inset-0 z-2 m-0 size-full cursor-ew-resize opacity-0" type="range" min="0" max="100" value="50" aria-label="Compare the raw and retouched shoe photo" aria-valuetext="50% after" data-compare-range>
        <span class="pointer-events-none absolute inset-y-0 left-(--x) z-1 w-0.5 -translate-x-1/2 bg-white shadow-[0_0_8px_rgba(0,0,0,.35)]" data-handle aria-hidden="true"></span>
        <span class="pointer-events-none absolute top-1/2 left-(--x) z-1 grid size-[38px] -translate-1/2 place-items-center rounded-full bg-white text-[#16181d] shadow-[0_3px_12px_rgba(0,0,0,.3)] peer-focus-visible:shadow-[0_0_0_3px_#fff] peer-focus-visible:outline-3 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-[#1d4ed8]" aria-hidden="true"><svg class="size-[18px]" viewBox="0 0 24 24"><path d="M9 6l-6 6 6 6M15 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
      </div>
  <div class="flex flex-col justify-center gap-3.5 px-[clamp(22px,4vw,44px)] py-[30px]">
    <p class="text-xs font-bold tracking-[.14em] text-[#f6a07a] uppercase">Pixelcraft Studio</p>
    <h3 id="prt-title" class="text-[1.65rem] leading-[1.15] font-bold tracking-[-.02em]">E-commerce product retouching</h3>
    <p class="leading-[1.55] text-[#c9c6bf]">Colour matched to the real product, so returns for “it looked different online” go down.</p>
    <ul class="grid gap-2 text-[.92rem]"><li class="flex items-baseline gap-2.5 before:size-2 before:flex-none before:-translate-y-px before:rounded-full before:bg-[#f6a07a]">Colour match against a physical sample</li><li class="flex items-baseline gap-2.5 before:size-2 before:flex-none before:-translate-y-px before:rounded-full before:bg-[#f6a07a]">Dust, lint and crease clean-up</li><li class="flex items-baseline gap-2.5 before:size-2 before:flex-none before:-translate-y-px before:rounded-full before:bg-[#f6a07a]">Background extension to any ratio</li></ul>
    <div class="mt-1.5 flex flex-wrap items-center justify-between gap-3 border-t border-[#33363d] pt-4"><div><small class="block text-[.8rem] text-[#b5b2ab]">From</small><strong class="text-[1.4rem]">$4.50 per image</strong></div><a class="inline-block rounded-full bg-[#f4f2ee] px-5 py-[11px] text-[.9rem] font-bold text-[#16181d] hover:bg-white focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-[#f6a07a]" href="#pricing">See pricing</a></div>
  </div>
</article></div>
CSS
/* The range value (0–100) is mirrored into --v; --x is the divider position, kept centred on the native thumb. */
@utility compare { --x: calc(var(--thumb) / 2 + (100% - var(--thumb)) * var(--v) / 100); }
@utility clip-before { clip-path: inset(0 calc(100% - var(--x)) 0 0); }
@utility compare-range {
  -webkit-appearance: none; appearance: none; background: none;
  &::-webkit-slider-runnable-track { height: 100%; }
  &::-webkit-slider-thumb { -webkit-appearance: none; width: var(--thumb); height: 100%; }
  &::-moz-range-thumb { width: var(--thumb); height: 100%; border: 0; }
}
JavaScript
// Before/after slider: the range input is the control. This mirrors its value into --v
// (which moves the divider and clip) and gives screen readers a readable value.
document.querySelectorAll('[data-compare]').forEach((root) => {
  const range = root.querySelector('[data-compare-range]');
  if (!range) return;
  const sync = () => {
    root.style.setProperty('--v', range.value);
    range.setAttribute('aria-valuetext', `${100 - range.value}% after`);
  };
  range.addEventListener('input', sync);
  sync();
});

About this set

Before and after sliders placed inside real page sections. Renovation before and after cards is an interior design studio’s recent work: three cards in a grid, one, two or three columns wide, each with a 4:3 comparison slider of a kitchen, a bathroom or a living room, a title, the street and town, and a budget and time line. Every photo is lazy-loaded and has srcset, sizes, width and height, so a long grid of projects stays light and does not shift while it loads. Product retouch showcase is a dark split card for a retouching service: a square comparison of a running shoe, raw on the left and retouched on the right, beside a short pitch, three bullet points, a price from line and a See pricing link. Use the cards for builders, landscapers, cleaners, stagers and photographers, and the split card for any service that sells a visible result. Each slider is the same native range input technique as the classic set, so every card can be dragged, swiped or moved with the arrow keys, and each has its own label naming the room or product.

What’s included

  • Grid of renovation cards with a comparison slider in each
  • Lazy-loaded photos with srcset, sizes, width and height
  • Budget and time details in a description list
  • Dark product retouching card with a pitch, bullets and a price line
  • Bootstrap version built from .card, .row-cols-* and .ratio

Accessibility

Each slider is a range input labelled with the room or product, for example Compare the kitchen before and after, with an aria-valuetext such as 50% after. The grid is a list of article elements with headings, and the budget and time are a description list. Handles and the See pricing link show a visible focus outline, and the label fade is switched off under prefers-reduced-motion.

Customise it

Change the --ic-before filter for the before look, --thumb for the hit area and the card colours in .rn-card and .pr. In Bootstrap edit .row-cols-sm-2 and .row-cols-lg-3 and the .ratio-4x3 stage; in Tailwind edit the grid-cols utilities and the filter classes on the before images.