Это оптимизация браузера. Ты когда css-стили накатываешь, они накапливаются, а применяются по окончанию js-функции. Поэтому нужно вызвать событие пересчёта значений css. Например, можно "дёрнуть" геттер
.clientWidth:
<div style="position: relative;">test</div>
<script>
var opts = {
obj: document.querySelector("div"),
property: "top",
delay: 0,
duration: 1000,
start: 0,
finish: 200
}
opts.obj.style.transitionProperty = opts.property;
opts.obj.style.transitionDelay = opts.delay + "ms";
opts.obj.style.transitionTimingFunction = "linear";
opts.obj.style.transitionDuration = opts.duration + "ms";
opts.obj.style[opts.property] = opts.start + "px";
opts.obj.clientWidth;
opts.obj.style[opts.property] = opts.finish + "px";
</script>