Посмотрите вот тут. Уже решал эту задачу. Вам нужно вычислить delta и применять ее каждый фрейм.
Анимировать N пикселей за T секунд
Для того, чтобы функция не нарисовала больше или меньше(она это сделает в любом случае). В условии
if (timePassed < duration) {
requestAnimationFrame(animate);
} else {
element.style['propertie'] = destination-position.
}
Нужно сделать вот такую вилку, которая по окончании всех действий просто жестко выставит положение в согласии с окончательным ожидаемым результатом. Это просто визуальный фикс для того чтобы исправить отклонения. Но иногда происходит рывок и этого пока как избежать я лично не придумал.