Skip to content

Instantly share code, notes, and snippets.

@greggman
Created December 23, 2025 02:56
Show Gist options
  • Select an option

  • Save greggman/bb8318545329b03b5d06ad06bb3d4ff0 to your computer and use it in GitHub Desktop.

Select an option

Save greggman/bb8318545329b03b5d06ad06bb3d4ff0 to your computer and use it in GitHub Desktop.
Canvas Comparison
/*bug-in-github-api-content-can-not-be-empty*/
<style>
.comparison-container {
position: relative;
width: 100%;
max-width: 800px; /* Optional: limit total size */
aspect-ratio: 16 / 9; /* Ensures the container has height */
overflow: hidden;
background: #eee;
}
/* Base styles for both canvases */
canvas {
display: block;
width: 100%;
height: 100%;
}
/* Top layer (The "Before" state) */
.overlay {
position: absolute;
inset: 0 auto 0 0;
width: 50%; /* Initial slider position */
overflow: hidden;
border-right: 2px solid white;
z-index: 1;
}
/* THE FIX: Prevents the canvas from resizing or sliding
when the .overlay container width changes */
.overlay canvas {
width: 100%;
height: 100%;
object-fit: cover;
object-position: left;
}
/* Invisible Slider Input */
.slider {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: ew-resize;
z-index: 2;
}
</style>
<div class="comparison-container">
<!-- Bottom Canvas (After) -->
<canvas id="canvasAfter"></canvas>
<!-- Top Canvas (Before) -->
<div class="overlay">
<canvas id="canvasBefore"></canvas>
</div>
<!-- The Control -->
<input type="range" min="0" max="100" value="50" class="slider" id="handle">
</div>
<script>
const canvasBefore = document.getElementById('canvasBefore');
const canvasAfter = document.getElementById('canvasAfter');
const handle = document.getElementById('handle');
const overlay = document.querySelector('.overlay');
// 1. Set internal resolution ONCE (e.g., 1000px wide)
// This behaves exactly like an image file's dimensions.
[canvasBefore, canvasAfter].forEach(canvas => {
canvas.width = 1600;
canvas.height = 900;
});
// 2. Render ONCE
const ctxB = canvasBefore.getContext('2d');
ctxB.fillStyle = '#3498db'; // Blue (Before)
ctxB.fillRect(0, 0, 1600, 900);
ctxB.fillStyle = 'white';
ctxB.font = 'bold 100px sans-serif';
ctxB.fillText('BEFORE (CANVAS)', 100, 450);
const ctxA = canvasAfter.getContext('2d');
ctxA.fillStyle = '#e74c3c'; // Red (After)
ctxA.fillRect(0, 0, 1600, 900);
ctxA.fillStyle = 'white';
ctxA.font = 'bold 100px sans-serif';
ctxA.fillText('AFTER (CANVAS)', 100, 450);
// 3. Simple Slider Logic
handle.addEventListener('input', (e) => {
overlay.style.width = `${e.target.value}%`;
});
</script>
/*bug-in-github-api-content-can-not-be-empty*/
{"name":"Canvas Comparison","settings":{},"filenames":["index.html","index.css","index.js"]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment