Side-by-side comparison of two website versions, with a draggable divider you slide to reveal one over the other.
A single-file, zero-build, zero-dependency tool for comparing two URLs visually. Drop the old version in one input, the new version in the other, and slide the divider in the middle — left side shows one site, right side shows the other, in the same viewport position. Perfect for showing clients a redesign, sanity-checking your own work against staging, or comparing competitors.
Live demo: https://cyberdemigods.github.io/web-transformation/
Built by CyberDemigods.
- Draggable divider — mouse, touch, or keyboard (
←→, withShiftfor 5% jumps,Home/Endfor edges) - Viewport emulator — switch between Desktop, Tablet (768px), and Mobile (390px) widths to test responsive behaviour
- Shareable links — Copy link button generates a URL with both addresses preconfigured (
?a=...&b=...&vp=tablet&lang=en), great for sending clients a ready-to-open comparison - Load time tracking — measures time from request to
loadevent for each iframe (best-effort: cross-origin iframes don't expose the full Performance API) - i18n — English and Polish UI, switchable from the toolbar; persisted in
localStorage; auto-detected fromnavigator.language - Swap & clear — quickly swap which URL is on which side, or reset
- Toast notifications — non-intrusive feedback instead of
alert() - No tracking, no analytics, no build step — opens straight from the filesystem
Pure vanilla HTML / CSS / JavaScript in a single index.html file. Uses:
iframe× 2 stacked withclip-path: inset(...)on the right one to reveal the left underneath. Modern browsers respectclip-pathfor hit-testing too, so clicks land on the visible side without proxy events.pointer-events: nonetoggled on iframes during drag, otherwise cross-origin iframes swallowmousemoveand the divider locks up when the cursor enters them.localStoragefor language preference, URL params for shareable state.- No external libraries. No npm. No build. Just open
index.html.
Many production websites block being loaded inside an iframe via X-Frame-Options: DENY/SAMEORIGIN headers or CSP frame-ancestors. When that happens, you'll see a blank white area instead of the page, with a console error like "Refused to display in a frame". This is a browser security feature and cannot be bypassed client-side. Workarounds (not implemented):
- Server-side proxy that strips the offending headers (legally grey, depending on your use case)
- Headless browser screenshots instead of live iframes (loses interactivity)
Scrolling one side does not scroll the other, because cross-origin iframes do not expose their contentWindow to the parent. We could implement scroll sync for same-origin pairs (e.g. staging vs production of your own site) via postMessage, but for arbitrary URLs it's not possible. In practice the two sites usually have different page heights anyway, so a synced scroll would drift quickly.
- Visit https://cyberdemigods.github.io/web-transformation/
- Paste two URLs (auto-prepends
https://if missing) - Hit Compare and drag the divider
git clone https://github.com/CyberDemigods/web-transformation
cd web-transformation
# That's it — open index.html in any modern browser
xdg-open index.html # or `open` on macOS, `start` on WindowsThere is no build step. Edit index.html, refresh the browser, you're done.
To serve over HTTP for testing (recommended on some browsers when iframe issues arise):
python3 -m http.server 8080
# then visit http://localhost:8080The app accepts these query parameters for deep-linking and embedding:
| Param | Values | Purpose |
|---|---|---|
a |
URL | Old / left-side site |
b |
URL | New / right-side site |
vp |
desktop, tablet, mobile |
Viewport width preset |
lang |
en, pl |
UI language (overrides browser default) |
Example: https://cyberdemigods.github.io/web-transformation/?a=https://example.com&b=https://example.org&vp=tablet&lang=pl
| Key | Action |
|---|---|
← / → |
Move divider by 1% |
Shift + ← / → |
Move divider by 5% |
Home |
Snap divider to far left (0%) |
End |
Snap divider to far right (100%) |
Enter (in URL field) |
Trigger comparison |
Tested on recent Chrome, Firefox, Edge, and Safari. Requires support for:
clip-path: inset()(all evergreen browsers)Pointer EventsandTouch EventslocalStorage,URLSearchParams,navigator.clipboard.writeText
The clipboard.writeText call has a document.execCommand('copy') fallback for older / restrictive contexts, and a final prompt() if even that fails.
- Horizontal split mode (top/bottom instead of left/right)
- Fade transition between A and B (slider controls opacity)
- Visual diff overlay highlighting changed regions
- PNG / PDF export of the current divider position
- Optional integration with Lachesis — show SEO/performance/accessibility audit metrics for both sides under the slider
Issues and PRs welcome. The codebase is intentionally one file, so the contribution surface is small and obvious. Please keep new dependencies to zero.
MIT — see LICENSE.
Forged by CyberDemigods.