# Before and After Comparison Slider: How to Build One (2026)

> How to build and embed a before-and-after comparison slider: matched exports, a native range input, pointer capture, keyboard access, and a QA checklist.

- Canonical HTML: https://revelraw.com/blog/before-after-comparison-slider.html
- Markdown mirror of this page: https://revelraw.com/blog/before-after-comparison-slider.md
- Published: 2026-09-21
- Language: English
- Machine-readable site index: https://revelraw.com/llms.txt · Full site as one file: https://revelraw.com/llms-full.txt

Published September 21, 2026 · Daniel Tello · RevelRaw

**Quick answer:** Export the before and the after from the same RAW file with an identical crop, pixel size and color space, or the seam will lie. Stack both images in one frame and clip the top one with a CSS custom property driven by a native `input type="range"`, so keyboard and screen-reader support come for free. On drag, use Pointer Events with `setPointerCapture()`, clamp the position to the frame, and give the handle a hit area of at least 44 by 44 points even if the visible line stays thin. Then test the seam on a real phone, not a desktop emulator.

You know the moment that makes a before-and-after comparison slider worth building. You lifted shadows on a sunset RAW, cooled the white balance a touch, backed off saturation, then toggled the original on and off until your eyes stopped trusting you. Side by side helps, but it also asks your brain to keep two full frames aligned while you judge tiny changes in sky color, skin texture, edge contrast, or local masking.

That's why this pattern stuck. A good comparison slider turns editing judgment into a single controlled reveal. Instead of blinking between two versions, you drag across one seam and inspect the exact boundary where the edit changes. If the grade works, the transition feels intentional. If it doesn't, halos, misalignment, muddy contrast, and overcooked sharpening show up immediately.

On the web, that simple interaction carries real expectations. It has to drag smoothly, work with touch as well as a mouse, stay aligned at the pixel level, and remain usable for people who don't drag at all. In a photo editor, the same pattern has a different job. It helps you decide whether the edit improved the image, not just whether the interaction looks slick.

## Why Editors Reach for a Slider in the First Place

You finish an edit, toggle back to the original, and hesitate. The grade felt right a second ago. Now the skin looks a little plastic, the sky looks a little flat, and you are no longer sure whether the problem is the edit or your eyes resetting between views.

That is the point where a slider earns its place.

### One moving seam is easier to judge than two separate frames

Editors reach for a slider because it turns comparison into inspection. Instead of asking your brain to remember one frame while looking at another, you drag a single boundary across the same composition and watch exactly where the edit starts to help or hurt.

That matters most on small, expensive decisions. Retouching around pores. Shadow recovery in dark fabric. Local contrast along a building edge. Noise reduction in hair. These are not broad mood changes. They live at the boundary.

Newsrooms and visual storytellers adopted the same pattern for then and now imagery because it lets the viewer trace change across one aligned frame instead of scanning two separate pictures, a use case Knight Lab documents for its [JuxtaposeJS](https://juxtapose.knightlab.com/) tool.

> A slider helps when the question is not "Did this image change?" but "Where does the change hold up under scrutiny?"

### The web version and the editor version solve the same problem

On the web, a before-and-after comparison slider is a UI control. In an editor, it is a judgment tool.

Those jobs overlap more than they look. A photographer needs the reveal line to stay perfectly aligned because a one or two pixel mismatch can read like bad sharpening or a sloppy mask. A front end build needs the same discipline for a different reason. If the layers drift, the component is lying to the user.

The same goes for motion. Dragging has to stay smooth enough that the divider feels attached to the image instead of lagging behind your finger or cursor. Keyboard access matters too, because a slider is still a slider. The WAI ARIA Authoring Practices define how that control should expose its value and keyboard behavior to assistive tech in the [ARIA slider pattern](https://www.w3.org/WAI/ARIA/apg/patterns/slider/).

### What a slider reveals that toggles and side by side views miss

Toggles are good for overall feel. Side by side views are good for broad comparison. A slider is better when the edit needs to survive close inspection in one exact spot.

- **Local adjustments:** The seam shows where dodge and burn starts looking obvious.
- **Retouching:** Cleanup either keeps texture at the transition or wipes it out.
- **Perspective fixes and crops:** Straight lines expose alignment mistakes fast.
- **Sharpening and denoise:** Fine detail loss shows up immediately in hair, foliage, and fabric.

That is why editors keep coming back to the pattern. It reduces memory load, exposes edge artifacts quickly, and translates well from a RAW workflow to a browser component people can use without instruction.

## The Anatomy of a Slider That Works

A good comparison slider holds up under two kinds of scrutiny at once. The photographer needs to judge edge detail, retouching, and local contrast without the UI getting in the way. The front end build needs to keep that judgment honest with stable geometry, smooth drag behavior, and controls people can operate on touch, keyboard, and assistive tech.

### Build the stack around one reveal edge

The reliable pattern is simple. Two perfectly aligned images share one frame. The bottom image stays fully visible. The top image is clipped, and the divider marks the clip boundary.

That layout does more than keep the code tidy. It gives the user one clear reference point. If the divider and the revealed edge ever separate visually, the component stops being trustworthy.

The default split should start in the center so both states are visible immediately. Keep **Before** and **After** labels on screen the whole time, and size the interactive handle for touch instead of only for the eye. Google's Android accessibility guidance, following Material Design, asks for touch targets of at least [48 by 48 dp](https://support.google.com/accessibility/android/answer/7101858), and Apple's design tips call for controls of at least [44 by 44 points](https://developer.apple.com/design/tips). Either is a good floor here.

### The handle is small art over a larger hit area

The visible handle can stay slim. The hit area should not.

That trade-off matters in real use. Photographers often want a clean divider that does not cover pores, hair, or product edges. Touch users need more room than that to grab the control reliably. The fix is straightforward. Keep the visual treatment narrow, then pad the interactive region invisibly around it.

A few implementation rules pay off every time:

- **Clamp movement to the image bounds:** The divider should stop at the left and right edges of the frame.
- **Attach drag to the frame, not the page:** Pointer movement should track against the image container so nearby text and controls do not interfere.
- **Let users drag the handle or the image area:** People often try the seam first, then the image itself.
- **Keep labels persistent:** Users should never have to remember which side is edited.

If the slider looks precise but feels annoying on a phone, the handle art is rarely the problem. The hit area is.

### Treat it like a reveal control, not a precision input

A comparison slider helps people inspect a change in one exact place. It does not help them choose an exact value. UX testing by [MeasuringU](https://measuringu.com/time-and-preference-numeric-slider-desktop-mobile/) found that sliders took about 37 percent longer to complete than simple radio-button controls, and respondents preferred the simpler control by more than two to one, on desktop and mobile alike.

That maps cleanly to image comparison work. The control should respond instantly, stay out of the way, and reveal content without extra chrome. Percentage badges, fixed readouts, and decorative animations usually add noise right where the viewer is trying to inspect the edit.

A temporary tooltip during drag can help. A permanent number in the middle of the photo usually hurts more than it helps.

## Preparing Your Before and After Images

You can build a fast, accessible slider and still publish a bad comparison. It happens when the files are not matched. The UI exposes every mismatch right at the seam, which is exactly where a photographer is trying to judge skin cleanup, local contrast, masking edges, or horizon corrections.

### Match the photo first

A before-and-after comparison slider works only when both states share the same geometry. Same frame, same crop, same aspect ratio, same pixel dimensions. If the subject shifts between versions, the viewer spends their attention decoding movement instead of evaluating the edit.

In practice, the trouble usually starts after the edit, not during development. A crop changes by a few pixels. Lens corrections differ between exports. One file gets an extra transform pass. On screen, that tiny drift looks like a broken component.

The fix is mechanical. Export both versions from the same base image and lock the crop before you render final files.

### Export for inspection, not just for delivery

Photo editors judge differences at edges and textures. Web UIs magnify mistakes there. Keep the pair as controlled as possible:

- **Match dimensions exactly:** One-pixel mismatches create a false edge at the reveal line.
- **Use the same color space:** sRGB keeps browser rendering predictable.
- **Start from the same RAW file:** Clear the edit state for the before version instead of using an older JPEG or camera preview.
- **Keep compression comparable:** If the before image is heavily compressed and the after is clean, viewers are comparing export damage as much as your edit.

If your export workflow is still inconsistent, this guide on [converting RAW to JPEG on Mac](https://revelraw.com/blog/convert-raw-to-jpeg-mac.md) is a useful reset before you wire those files into a slider.

### Check alignment where edits actually get judged

Do not verify alignment by looking at the whole frame and calling it close enough. Check the spots people inspect. Eyes. Rooflines. Jawlines. Product edges. Window frames. Those are the places where a compare view earns its keep, and they are also where misregistration shows up first.

I usually zoom in and scrub between versions before export. If the image jumps, the slider will jump. That is true whether the compare view lives on a portfolio site or inside a photo app.

A small naming habit also prevents avoidable mistakes. Use filenames such as `before.jpg` and `after.jpg`, or a clear variant pair from your export preset. It will not improve the image, but it does stop the common failure where the same file gets wired into both layers or the edit order gets reversed.

## Building the Slider From Markup to Drag Logic

A comparison slider fails fast when the interaction gets in the way of the judgment. If the handle stutters, slips off your finger, or hides the exact edge you are trying to inspect, the edit becomes harder to read than a simple side-by-side. Good builds keep the UI quiet so the image difference stays obvious.

### Markup that carries its own meaning

Use plain structure first. A wrapper, two aligned images, and one real control are enough.

```
`<div class="compare" aria-label="Before and after photo comparison">
  <img src="before.jpg" alt="Before edit" class="compare__base">
  <div class="compare__overlay" style="--split: 50%">
    <img src="after.jpg" alt="After edit" class="compare__top">
  </div>

  <input
    type="range"
    class="compare__range"
    min="0"
    max="100"
    value="50"
    aria-label="Reveal edited image"
    aria-valuetext="Before 50 percent, after 50 percent">
</div>`
```

I prefer a native `input[type="range"]` over a custom `div` with `role="slider"` unless the design demands otherwise. You get keyboard behavior, form semantics, and a lot of accessibility work for free. Then style around it. The visible handle can still look custom, but the underlying control behaves like a slider should.

For the layout, stack both images in a relatively positioned wrapper and clip the top layer with a CSS custom property. JavaScript should update one value. That keeps state simple and cuts down on DOM churn during drag.

### Pointer logic that survives real use

The drag math is simple. The edge cases are not.

Read `clientX`, subtract the container's left edge, clamp the result between `0` and the container width, then convert that to a percentage. Update the clip position and the handle from the same value so they never drift apart. On touch screens, increase the hit area beyond the visible knob. Photographers often drag slowly around eyes, hairlines, horizon edges, or product contours. A tiny handle feels precise in a mockup and frustrating on a phone.

If you build a custom pointer layer on top of the range input, use Pointer Events and call `setPointerCapture()` on `pointerdown`. That single detail prevents the common failure where the drag drops as soon as the pointer leaves the handle by a few pixels.

| Input detail | What to do |
| --- | --- |
| Pointer position | Read `clientX` relative to the wrapper |
| Out-of-bounds drag | Clamp to the left or right edge |
| State value | Convert to a percentage |
| Render update | Write one CSS variable for the reveal position |
| Assistive state | Keep the slider value and text in sync |

A tap-to-position track also helps. On mobile, people expect the divider to jump close to the point they touched, then allow fine adjustment.

If you want a framework-specific reference for how a slider value and DOM state stay tied together, this [Vue range slider tutorial](https://getdom.studio/blog/vue-range-slider) is useful because it shows the state-management side cleanly, even though a compare UI still needs custom rendering on top.

### Keep the motion clean

The reveal should track the finger without visible lag. In practice that means light JavaScript, one source of truth for position, and visual updates that do not trigger expensive layout work every frame.

Use `requestAnimationFrame` if pointer events are firing faster than your rendering path can keep up. Move the handle with transforms. Update the reveal mask or clipped width from the same state. Test on an actual phone, not just a desktop browser with device emulation. Many sliders feel fine with a mouse and fall apart under a thumb because the touch target is too narrow or the frame rate drops once large images load.

For a small working example of the pattern, the drag-to-compare noise card on the [RevelRaw homepage](https://revelraw.com/index.md#denoise) uses the same one-seam layout. It is a useful place to feel divider behavior and hit area on a phone, and to check whether the reveal line stays visually stable while you scrub across detail.

## Accessibility and Performance Most Builds Skip

Open a before-and-after slider on a phone in bright sunlight and the weak builds show themselves fast. The handle is too small to grab. The divider glides with pretty easing instead of staying under your thumb. VoiceOver announces “slider” but gives no useful context. For a photographer trying to judge edge detail, skin tone, or highlight recovery, that is not a styling problem. It breaks the compare.

A usable slider borrows from two worlds at once. On the web, it needs the basics people expect from any control: keyboard support, visible focus, enough hit area, and clear names and values for assistive tech. In an editor, it also has to stay honest while you scrub across fine detail. If motion lags or the reveal line jitters, viewers start doubting the edit instead of evaluating it.

The baseline is straightforward. Use the ARIA slider pattern correctly, keep the current value exposed, and make the control operable without drag input. The [WAI-ARIA Authoring Practices slider pattern](https://www.w3.org/WAI/ARIA/apg/patterns/slider/) is the reference worth following here because it covers naming, keyboard behavior, and expected state.

A few implementation choices separate a demo from a tool people can use:

- **Support more than drag.** Arrow keys should move in small steps. Home and End should jump to the bounds. A tap target around the handle should be forgiving on touch screens.
- **Expose meaningful labels.** “Before/after position” is better than a generic “slider,” and text nearby should make the two states obvious.
- **Offer another inspection path.** A simple side-by-side or stacked fallback helps users who cannot drag precisely and helps everyone when they want to compare a fixed area.
- **Respect motion settings.** If the OS requests reduced motion, move the divider directly to the new position instead of animating the travel.

Performance is part of accessibility here. A slider that drops frames under touch input is harder to use, and a delayed decode on one image makes the first interaction look broken. I treat compare sliders the same way I treat a zoomable photo viewer. Keep visual updates on the compositor when possible, avoid per-frame layout work, and test on a real phone with full-size exports, not just desktop DevTools.

The [web.dev performance guides](https://web.dev/fast/#optimize-your-images) cover the same ground: serve images at the right dimensions, pick a sensible compression level, and lazy-load sliders that sit below the fold so the page does not pay for every comparison at once.

Upstream image prep matters too. If the export is oversharpened, crushed by compression, or color-shifted for social delivery, the slider ends up showcasing export damage instead of the edit. A practical reference on [Instagram export settings for edited photos](https://revelraw.com/blog/best-instagram-export-settings.md) helps keep that failure out of the compare view.

## Web Embed Versus an In-App Compare View

A slider on a portfolio page gets used very differently from a compare view inside a RAW editor. On the web, the reader asks, "What changed?" In the editor, the photographer asks, "Did this edit hold up at the pixel level?"

That difference matters because the UI can look similar while the job is completely different.

### What the web embed is good at

A web embed is a publishing format. It belongs in a case study, product page, client proof, or article where someone needs to inspect the result in a browser and understand the edit fast. The interaction can be simple as long as it feels good on touch, stays responsive, and makes the transformation obvious on the first drag.

It also has hard limits. The browser is comparing exports, usually JPEG, AVIF, or WebP, not the live edit stack. If the export clipped highlights, softened fine detail, or shifted color, the slider shows those mistakes too. I have seen strong edits look weak in a web compare because the output files were downsampled too aggressively and the seam ran right through the area where texture mattered.

A web slider is also public-facing UI. It has to survive responsive layouts, mobile thumbs, and distracted readers. That pushes the build toward clear affordances and fast rendering, not the dense inspection tools an editor can support.

### What the in-app compare view keeps alive

Inside a RAW editor, compare is part of the editing workflow. You are checking whether your recovery work introduced gray highlights, whether local masking left a hard edge, whether noise reduction smeared eyelashes, or whether your color grade drifted away from the scene.

That is why an in-app compare view can be more demanding than a web slider. It sits next to the tools that caused the change, and it has to support actual judgment, not just presentation. Side-by-side, split view, zoom parity, and quick toggling all help because the editor is trying to verify decisions, not tell a story.

RevelRaw is one example of that model. It offers a before/after comparison with a slider mode and a side-by-side mode inside a macOS RAW workflow, so the edit gets judged against the original before anything is exported.

Use the web slider to present the final result. Use the editor compare view to decide whether the result is ready to publish.

### Web Embed vs In-App Compare View

| Dimension | Web Embed | In-App Compare View |
| --- | --- | --- |
| Primary job | Show results to viewers | Judge edits while working |
| Source material | Exported image files | Original RAW plus current edit state |
| Interaction priority | Responsive drag, touch comfort, browser compatibility | Fast toggling, zoom checks, tool-adjacent review |
| Inspection depth | Good for obvious visible changes | Better for exposure, color, masking, sharpening, and noise decisions |
| Accessibility needs | ARIA labeling, keyboard support, mobile targets | Keyboard speed, pane consistency, predictable shortcuts |
| Performance target | Smooth browser interaction on real devices | Smooth redraw while edits and previews update |
| Best use | Portfolios, case studies, client-facing proof | Editing choices before export |

The mistake is using one in place of the other. If you judge a delicate edit from compressed web exports, you can approve halos, mushy detail, or color shifts that were not in the RAW workflow. If you stop at the in-app compare and never publish an interactive result, readers lose the fastest way to understand what your edit changed.

## A Final QA Checklist Before You Publish

A slider can pass a quick desktop check and still fail the moment a reader drags it on a phone or tries to inspect a fine edge in the image. Publish only after testing it like both a UI control and a photo judgment tool.

I use this pass to catch two kinds of failures. The first is mechanical: bad touch targets, clipped handles, broken keyboard input, stutter during drag. The second is photographic: misregistered crops, sharpening halos that only show up at the seam, or compression that makes the after image look worse than the edit.

### Five checks worth doing every time

- **Image parity:** Confirm identical pixel dimensions, crop, orientation, and color profile. If the split line wobbles across an eye, roofline, or product edge, export the pair again.
- **Edge behavior:** Drag the divider fully left and fully right. The handle should stay in bounds, the revealed image should not flash past the container, and the split should stay clean at both limits.
- **Keyboard and focus:** Tab to the slider, move it with arrow keys, and check that the focus state stays visible over light and dark image areas. Screen reader labeling should still make sense without seeing the photos.
- **Motion and frame rate:** Drag on a real phone, not only in desktop devtools. The interaction should feel smooth, and reduced-motion users should get the same control without extra animated travel.
- **Static fallback:** Social cards, email embeds, and some CMS previews flatten the experience to one frame. Pick a poster frame that still communicates the edit without interaction.

Test narrow and wide layouts before you call it done. Mobile catches target-size and overflow problems. Large, sharp displays catch edge halos, mask mistakes, and JPEG seams that a smaller screen hides.

If one of those checks fails, readers will notice the slider before they notice the edit. Fix the export, the interaction, or both, then publish.

If you want the editing side of this workflow, RevelRaw gives Mac photographers an on-device RAW editor with a slider mode and a side-by-side mode for before/after comparison, plus export presets for Instagram, Flickr, 500px, Adobe Stock, print and web that make a matched pair easy to produce. You can see what it offers and decide whether it fits your process at [RevelRaw](https://revelraw.com).

## FAQ

### Do I need JavaScript for a before-and-after comparison slider?

A little. Two stacked images and a native range input give you the control and its keyboard behavior, but nothing clips the top image until a script reads the slider value and writes it to one CSS custom property. That single handler is all the JavaScript the core pattern needs; Pointer Events and tap-to-position are refinements on top of it.

### Should I use a native range input or a custom div with role="slider"?

Default to the native input. It gives you focus, arrow-key steps, Home and End, form semantics and a value assistive technology can read, with no extra code. Build a custom element only when the design truly demands it, and then implement the full WAI-ARIA slider pattern: role, value attributes, keyboard handling and a visible focus state.

### Why is there a thin misaligned line at the seam?

The two files do not share the same geometry. A crop that shifted by a pixel, lens corrections applied to one export but not the other, or a resize pass on only one file all produce a hard edge at the reveal line. Export both versions from the same base image, lock the crop first, and confirm identical pixel dimensions before wiring them in.

### How do I make the slider work on touch screens?

Use Pointer Events instead of separate mouse and touch handlers, call setPointerCapture() on pointerdown so the drag survives a finger leaving the handle, and set touch-action: none on the track so the page does not scroll mid-drag. Pad the hit area well beyond the visible line, let a tap jump the divider to that spot, and test on a real phone.

### Does RevelRaw have a before-and-after comparison view?

Yes. RevelRaw is an on-device RAW editor for the Mac with a before/after comparison that offers a slider mode and a side-by-side mode, so an edit can be judged against the original before export. It requires macOS 26 or later on an Apple M1 Mac or newer and is a free download with one free full-quality export.

**Ready to edit your RAW files?** RevelRaw reads the scene and ranks 40+ curated presets for that photograph. Free to download, with one free export to try the full workflow. [Get RevelRaw on the Mac App Store](https://apps.apple.com/app/apple-store/id6773942240?pt=120914369&ct=BlogCompareSlider&mt=8) (requires macOS 26 and an Apple M1 Mac or later).
