为什么ScrollTop位置在移动Safari上不起作用?

我的网站上有一个功能,徽标会根据用户在网站上的位置垂直滚动。

您可以看到它在Chrome {{3}}上运行

但是它不适用于Safari(包括手机和平板电脑)。

控制台中的滚动位置似乎根本没有改变。

// logo positioning  

let logos,logoHeight,barTopMargin;
let viewportHeight;

window.addEventListener('load',init);
window.addEventListener('resize',setSizes);
document.addEventListener('scroll',update);


function init(lockUpdate) {
    logos = document.querySelectorAll('.scroll-text');
    setSizes(lockUpdate);
}

function update() {
    // ensure initialization and prevent recursive call
    if (!logos) init(true);
    //*************************************************

    /**************************************************
        THIS LINE MUST BE HERE.
    **************************************************/
    let maxScrollDist  = document.documentElement.scrollHeight - viewportHeight;
    //*************************************************

    let currentScrollPos = document.documentElement.scrollTop;
    let newTop;

    let middle = currentScrollPos + viewportHeight/2;
    let middleY = maxScrollDist/2;

    if (middle >= (maxScrollDist+viewportHeight)/2) {
        let p = (middleY - Math.floor(middle - (maxScrollDist+viewportHeight)/2))*100/middleY;

        newTop = viewportHeight/2 - logoHeight/2;
        newTop += (100-p)*(viewportHeight/2)/100;
        newTop -= (100-p)*(barTopMargin +logoHeight/2)/100;
        newTop = Math.max(newTop,viewportHeight/2 - logoHeight/2); /*fix*/
    } else {
        let p = (middleY - Math.floor(-middle + (maxScrollDist+viewportHeight)/2))*100/middleY;
        newTop = barTopMargin*(100-p)/100+(viewportHeight/2 - (logoHeight/2)*p/100 )*p/100;
        newTop = Math.min(newTop,viewportHeight/2 - logoHeight/2); /*fix*/
    }

    logos.forEach(function(el) {
        el.style.top = newTop + "px";
    });
}

function setSizes(lockUpdate) {
    logoHeight     = logos[0].offsetHeight;
    barTopMargin   = parseInt(getcomputedStyle(document.querySelector('#page'),'::before').top);
    viewportHeight = window.innerHeight;
    if (lockUpdate === true) return;
    update();
}
zsdgr89456789000zzh7 回答:为什么ScrollTop位置在移动Safari上不起作用?

此行为背后的原因在于浏览器之间滚动实现的差异。例如,Chrome根据<html>计算页面滚动,而Safari在<body>上进行页面滚动。

Chrome浏览器:

chrome scrollingElement

Safari:

safari scrollingElement

考虑到此信息,可以合理地假设在Safari document.documentElement中完全不知道页面的全局滚动值。

要解决此问题,您可以定义一个辅助函数,该函数使用document.scrollingElement并在getBoundingClientRect上回退到document.documentElement

function getScrollingElement() {
  if (document.scrollingElement) {
    return document.scrollingElement;
  }

  const docElement = document.documentElement;
  const docElementRect = docElement.getBoundingClientRect();

  return {
    scrollHeight: Math.ceil(docElementRect.height),scrollTop: Math.abs(docElementRect.top)
  }
}

并在您的update函数中使用它:

function update() {
  // ensure initialization and prevent recursive call
  if (!logos) init(true);
  //*************************************************

  /**************************************************
      THIS LINE MUST BE HERE.
  **************************************************/
  let maxScrollDist = getScrollingElement().scrollHeight - viewportHeight;
  //*************************************************

  let currentScrollPos = getScrollingElement().scrollTop;

  // ...
}

function getScrollingElement() {
  // ...
}

完整代码:

// logo positioning  

let logos,logoHeight,barTopMargin;
let viewportHeight;

window.addEventListener('load',init);
window.addEventListener('resize',setSizes);
document.addEventListener('scroll',update);


function init(lockUpdate) {
    logos = document.querySelectorAll('.scroll-text');
    setSizes(lockUpdate);
}

function update() {
    // ensure initialization and prevent recursive call
    if (!logos) init(true);
    //*************************************************

    /**************************************************
        THIS LINE MUST BE HERE.
    **************************************************/
    let maxScrollDist  = getScrollingElement().scrollHeight - viewportHeight;
    //*************************************************

    let currentScrollPos = getScrollingElement().scrollTop;
    let newTop;

    let middle = currentScrollPos + viewportHeight/2;
    let middleY = maxScrollDist/2;

    if (middle >= (maxScrollDist+viewportHeight)/2) {
        let p = (middleY - Math.floor(middle - (maxScrollDist+viewportHeight)/2))*100/middleY;

        newTop = viewportHeight/2 - logoHeight/2;
        newTop += (100-p)*(viewportHeight/2)/100;
        newTop -= (100-p)*(barTopMargin +logoHeight/2)/100;
        newTop = Math.max(newTop,viewportHeight/2 - logoHeight/2); /*fix*/
    } else {
        let p = (middleY - Math.floor(-middle + (maxScrollDist+viewportHeight)/2))*100/middleY;
        newTop = barTopMargin*(100-p)/100+(viewportHeight/2 - (logoHeight/2)*p/100 )*p/100;
        newTop = Math.min(newTop,viewportHeight/2 - logoHeight/2); /*fix*/
    }

    logos.forEach(function(el) {
        el.style.top = newTop + "px";
    });
}

function getScrollingElement() {
  if (document.scrollingElement) {
    return document.scrollingElement;
  }

  const docElement = document.documentElement;
  const docElementRect = docElement.getBoundingClientRect();

  return {
    scrollHeight: Math.ceil(docElementRect.height),scrollTop: Math.abs(docElementRect.top)
  }
}

function setSizes(lockUpdate) {
    logoHeight     = logos[0].offsetHeight;
    barTopMargin   = parseInt(getComputedStyle(document.querySelector('#page'),'::before').top);
    viewportHeight = window.innerHeight;
    if (lockUpdate === true) return;
    update();
}

希望这会有所帮助。

本文链接:https://www.f2er.com/3166804.html

大家都在问