JSFiddle - React, Tailwind, and code Playground
by Pangur Ban
HTML
<div class="viewport">
<div class="viewport-inner">
<div class="wrapper">
<div class="canvas">canvas</div>
<div class="box1"></div>
<div class="box2"></div>
<div class="box3"></div>
<div class="box4"></div>
<div class="box5"></div>
</div>
</div>
</div>
CSS
.viewport {
width: 300px;
height: 300px;
border: 2px solid red;
overflow: auto;
position: relative;
}
.viewport-inner {
margin: 20px;
display: inline-block;
}
.wrapper {
position: relative;
}
.canvas {
position: absolute;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.1);
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 viewportEl = document.querySelector('.viewport');
const wrapperEl = document.querySelector('.wrapper');
const canvasEl = document.querySelector('.canvas');
const MARGIN = 20;
const wrapperWidth = 600;
const wrapperHeight = 600;
wrapperEl.style.width = `${wrapperWidth}px`;
wrapperEl.style.height = `${wrapperHeight}px`;
const viewportWidth = viewportEl.clientWidth;
const viewportHeight = viewportEl.clientHeight;
let left = 0;
if (wrapperWidth < viewportWidth) {
left = (viewportWidth - wrapperWidth) / 2;
left -= 20;
}
const canvasWidth = Math.min(wrapperWidth, viewportWidth);
const canvasHeight = Math.min(wrapperHeight, viewportHeight);
const leftLimit = wrapperWidth - canvasWidth + MARGIN;
const topLimit = wrapperHeight - canvasHeight + MARGIN;
canvasEl.style.width = `${canvasWidth}px`;
canvasEl.style.height = `${canvasHeight}px`;
wrapperEl.style.left = `${left}px`;
viewportEl.addEventListener('scroll', onScroll);
onScroll();
function onScroll() {
let scrollLeft = viewportEl.scrollLeft;
let scrollTop = viewportEl.scrollTop;
scrollLeft = (scrollLeft > leftLimit) ? leftLimit : scrollLeft;
scrollTop = (scrollTop > topLimit) ? topLimit : scrollTop;
if (scrollLeft < MARGIN) {
scrollLeft = 0;
} else {
scrollLeft -= MARGIN;
}
if (scrollTop < MARGIN) {
scrollTop = 0;
} else {
scrollTop -= MARGIN;
}
canvasEl.style.left = `${scrollLeft}px`;
canvasEl.style.top = `${scrollTop}px`;
}