Анимацию через requestAnimationFrame нужно делать
<!DOCTYPE html>
<html>
<head>
<style>
#red {
position: absolute;
width: 25px;
height: 25px;
background-color: red;
}
body {
height: 100%;
}
</style>
</head>
<body>
<div id="red"></div>
<button id="start">Start</button>
<script>
let box= document.getElementById('red');
const boxrect = box.getBoundingClientRect();
const boxWidth = boxrect.width;
const boxHeight = boxrect.height
const windowWidth=innerWidth;
const windowHeight=innerHeight;
const x0 = (windowWidth - boxWidth)/2;
const y0 = (windowHeight - boxHeight)/2
box.style.left = x0 + 'px';
box.style.top = y0 + 'px';
let direction = 'up';
const rightX = windowWidth - boxWidth;
const bottomY = windowHeight - boxHeight;
const speed = 100; // px/s
let lastT;
let curX = x0;
let curY = y0;
const move = (nowT) => {
if (lastT === undefined) lastT = nowT;
let stop = false;
const dt = nowT - lastT;
const d = speed * dt / 1000;
lastT = nowT;
switch (direction) {
case 'up':
if (curY <= y0) {
curY = Math.max(curY - d, 0);
if (curY == 0) direction = 'right';
} else {
curY = Math.max(curY - d, y0);
if (curY == y0) stop = true;
}
break;
case 'right' :
curX = Math.min(curX + d, rightX);
if (curX == rightX) direction = 'down';
break;
case 'down':
curY = Math.min (curY + d, bottomY);
if (curY == bottomY) direction = 'left';
break
case 'left' :
curX = Math.max(curX - d, x0);
if (curX == x0) direction = 'up';
break;
}
box.style.top = curY + 'px';
box.style.left = curX + 'px';
if (!stop)
requestAnimationFrame(move);
else
lastT = undefined;
}
const start = document.getElementById('start');
start.addEventListener ('click', () => requestAnimationFrame(move))
</script>
</body>
</html>