JSFiddle - React, Tailwind, and code Playground
by Pangur Ban
HTML
<div class="viewport">
<div class="canvas">canvas</div>
<div class="scroll">
<div class="scroll-inner">
<div class="padding">
<div class="box1"></div>
<div class="box2"></div>
<div class="box3"></div>
<div class="box4"></div>
<div class="box5"></div>
</div>
</div>
</div>
</div>
CSS
* {
box-sizing: border-box;
}
.viewport {
width: 300px;
height: 300px;
border: 2px solid red;
position: relative;
overflow: hidden;
}
.scroll {
position: relative;
z-index: 100;
height: 100%;
overflow: auto;
}
.scroll-inner {
margin: 20px;
}
.padding {
position: relative;
margin: auto;
}
.canvas {
background: rgba(0, 0, 0, 0.1);
position: absolute;
top: 0;
left: 0;
font: 30px sans-serif;
line-height: 300px;
text-align: center;
}
[class^=box] {
position: absolute;
width: 100px;
height: 40px;
border: 2px solid #999;
}
.box1 {
top: 0;
left: 0;
}
.box2 {
top: 0;
right: 0;
}
.box3 {
bottom: 0;
left: 0;
}
.box4 {
bottom: 0;
right: 0;
}
.box5 {
transform: translate(-50%, -50%);
left: 50%;
top: 50%;
}
Babel + JSX
const scrollEl = document.querySelector('.scroll');
const canvasEl = document.querySelector('.canvas');
const paddingEl = document.querySelector('.padding');
const OFFSET = 20;
const width = 600;
const height = 600;
paddingEl.style.width = `${width}px`;
paddingEl.style.height = `${height}px`;
let left = 0;
if (width < scrollEl.clientWidth) {
left = (scrollEl.clientWidth - width) / 2;
left -= 20;
}
canvasEl.style.width = `${Math.min(scrollEl.clientWidth, width)}px`;
canvasEl.style.height = `${Math.min(scrollEl.clientHeight, height)}px`;
canvasEl.style.left = `${left}px`;
onScroll();
scrollEl.addEventListener('scroll', onScroll);
function onScroll() {
const top = scrollEl.scrollTop;
const bottom = scrollEl.scrollHeight - scrollEl.scrollTop - scrollEl.clientHeight;
const left = scrollEl.scrollLeft;
let y = 0;
if (top <= OFFSET) {
y = OFFSET - top
} else if (bottom <= OFFSET) {
y = -(OFFSET - bottom)
}
let x = 0;
if (left <= OFFSET) {
x = OFFSET - left;
}
canvasEl.style.transform = `translate3d(${x}px, ${y}px, 0)`;
/* do render */
}