Тормозит плавный скролл js на телефоне
Мне нужно сделать плавный скролл. scroll-behavior: smooth; и window.scrollTo({ top: to, behavior: "smooth" }); - не подходит т.к. не поддерживается в Safari. Делал по такой схеме:
- Получаю положение элемента (где он находиться относительно всей страницы по высоте)
- Получаю
window.pageYOffset- текущее положение вьюпорта. - Вычисляю дистанцию.
- Через
window.scrollByскроллю вниз надистанция/скорость - Повторяю выше указанные действия если расстояние до цели больше шага прокрутки через
setTimeout.
На пк всё работает нормально, скроллиться с замедлением до элемента плавно. На телефоне же (реальном, не DevTools) - лагает. Почему так и что можно сделать?
Использование библиотек крайне не желательно.
Вот код:
class jscroll {
static to(item)
{
const stepCoefficient = 100;
const timer = 1;
let to = document.querySelector(item).getBoundingClientRect().top;
let distance = to - window.pageYOffset + stepCoefficient;
let step = 10;
let oldStep;
function scroll() {
oldStep = step;
step = distance / stepCoefficient;
window.scrollBy(0, step);
distance = to - window.pageYOffset + stepCoefficient;
if (step > 1 && step != oldStep)
setTimeout(scroll, timer);
else
window.scrollTo(0, to);
}
scroll();
}
}
export { jscroll }
Ответы (2 шт):
Попробуй вместо
window.scrollTo(0, to);
выбрать какой-то самый верхний елемент (например хедер)
и скролить к нему так:
scrollTargetEl.scrollIntoView({
behavior: 'smooth',
block: 'start',
});
у меня есть проект где такой способ работает везде.
И тогда вам не нужно будет писать костили static to(item)
Проверено на мобильном устройстве.
Думаю, причиной неплавной работы может служить слишком частый вызов функции (всего 1 миллисекунда задержки перед новым выполнением). Вызывать её следует примерно в 17 раз реже (для обыкновенного экрана с частотой 60 Гц). С помощью window.requestAnimationFrame можно делать вызовы, которые "чаще всего совпадают с частотой обновления экрана" и не перегружать устройство.
В моём примере нумерация облегчает проверку плавности. Переменная offset ответственна за отступ, а speed - за скорость пролистывания.
function scrollTo(item) {
let offset = 0;
let speed = 20;
let to = document.querySelector(item).getBoundingClientRect().top;
let dy = to - window.pageYOffset + offset;
let moreZero = (dy >= 0)? 1 : -1;
let dist = dy * moreZero;
let step = speed * moreZero;
window.requestAnimationFrame((scroll = function() {
if ((dist -= speed) > 0) {
window.scrollBy(0, step);
window.requestAnimationFrame(scroll);
}
}));
}
document.getElementsByTagName("button")[0].onclick = () => {
scrollTo("#l");
}
// ниже - создание элементов для проверки
function createDivs() {
for (let i = 0; i < 200; i++) {
let e = document.createElement("div");
e.innerHTML = i;
document.body.appendChild(e);
}
let e = document.createElement("div");
e.id = "l";
document.body.appendChild(e);
}
createDivs();
<button>Scroll</button>