【问题标题】:Consistent scroll behavior across browsers跨浏览器的一致滚动行为
【发布时间】:2017-06-09 12:00:12
【问题描述】:

我做了这个pen 来模拟这个问题。

function createBox() {
  var box = document.createElement("div");
  box.className = "box";
  box.style.backgroundColor = "#"+((1<<24)*Math.random()|0).toString(16);
  
  return box;
}

function prependInnerHTML() {
  console.log('prependInnerHTML'); 
  var element = document.getElementById('scroll');
  var box = createBox();
  element.innerHTML = box.outerHTML + element.innerHTML;
  element.prepend(box);
}

function prependPrepend() {
  console.log('prependPrepend'); 
  var element = document.getElementById('scroll');
  var box = createBox();
  element.prepend(box);
}

function prependPrepend() {
  console.log('prependPrepend'); 
  var element = document.getElementById('scroll');
  var box = createBox();
  element.prepend(box);
}

function prependInsertBefore() {
  console.log('prependInsertBefore'); 
  var element = document.getElementById('scroll');
  var box = createBox();
  element.insertBefore(box, element.firstChild);
}

function scroll() {
  console.log('scroll');
  var detailElement = document.getElementById('details');
  var scrollElement = document.getElementById('scroll');
  
  detailElement.innerHTML = "ScrollTop: " + scrollElement.scrollTop;
}

function clearScrollElement() {
  console.log('clear');
  var element = document.getElementById('scroll');
    while(element.firstChild){
      element.removeChild(element.firstChild);
  }
}
html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  width: 100%
}
#details {
  position: fixed;
  top: 10px;
  left: 20px;
  background-color: white;
}
#options {
  position: fixed;
  top: 10px;
  right: 20px;
  background-color: white;
}
#scroll {
  overflow-x: hidden;
  overflow-y: scroll;
  height: 100%;
  width: 100%;
}
.box {
  height: 100vh;
  width: 100%
}
<div id="options">
  <span onclick="prependInnerHTML()">InnerHTML</span>
  <span onclick="prependInsertBefore()">InsertBefore</span>
  <span onclick="prependPrepend()">Prepend</span>
  <span onclick="clearScrollElement()">Clear</span>
</div>

<div id="details">
  ScrollTop: 0
</div>

<div id="scroll" onscroll="scroll()"></div>

问题是当一个元素被附加到一个可滚动元素时,它在不同的浏览器中会有不同的行为。

innerHTML:

第一个 prepend 方法是改变可滚动元素的 innerHTML。这似乎在多个浏览器中是一致的。

问题是像 Vue 这样的框架在内部没有使用这种方法,它可能使用其他方法之一。

使用 Chrome 插入之前:

如果 scrollTop 为 0 并且我们预先设置 scrollTop 保持为零。如果 scrollTop 大于零,它将调整 scrollTop 以包含前置元素的高度。

在 IE/Edge/Firefox 中插入之前:

与 innerHTML 的行为相同。

前置:

在 IE/Edge 上似乎不支持 Prepend,所以我会跳过那个。

问题:

如何在不引入各种浏览器检查的情况下使 InsertBefore 在所有浏览器中表现相同?

【问题讨论】:

  • 听起来像是 chrome 的滚动锚定。我相信自 v56 以来它现在默认开启。您可以尝试将其关闭以查看是否可以使浏览器之间的行为正常化,然后从那里开始。您可以在这里阅读一些相关信息:developers.google.com/web/updates/2016/04/scroll-anchoring
  • @AtheistP3ace 这很可能是导致问题的原因。看起来我可以使用 overflow-anchor: none CSS 属性来解决问题。
  • 甜蜜!很高兴你能弄清楚!祝你好运。

标签: javascript


【解决方案1】:

尝试这样做

/**
 * Adds a new element to the top of the container, If after is a valid element then the new element is added after that element
 * @param {HTMLElement} newItem - newItem to be added
 * @param {HTMLElement} container - container
 * @param {HTMLElement} [after=] - optional parameter, states that the new item will be added after this element
 * @returns {HTMLElement}
 */
function addElementToTop(newItem, container, after) {
    if (after instanceof HTMLElement === false || after.parentElement !== container) {
        var first = container.firstElementChild;
    } else {
        first = after.nextElementSibling;
    }
    if (first !== null) {
        container.insertBefore(newItem, first);
    } else {
        container.appendChild(newItem);
    }
    return newItem;
}

这是简单的版本

function addElementToTop(newItem, container) {
    var first = container.firstElementChild;
    if (first) container.insertBefore(newItem, first);
    else container.appendChild(newItem);
    return newItem;
}

以下版本保持相同的视口,但滚动变化

function addElementToTopSteadyScroll(newItem, container) {
    var bot = container.scrollHeight - container.scrollTop;
    var first = container.firstElementChild;
    if (first) container.insertBefore(newItem, first);
    else container.appendChild(newItem);
    container.scrollTop = container.scrollHeight - bot;
    return newItem;
}

而以下版本保持相同的滚动,但视口改变

function addElementToTopFlowScroll(newItem, container) {
    var top = container.scrollTop;
    var first = container.firstElementChild;
    if (first) container.insertBefore(newItem, first);
    else container.appendChild(newItem);
    container.scrollTop = top;
    return newItem;
}

【讨论】:

  • 我不明白。它追加而不是前置?修复跨浏览器滚动不一致的代码怎么样?
  • 在不同浏览器之间仍然不一致。(在 Chrome 和 Edge 上测试)
  • @Niels 新增2个功能,看看有没有适合你的功能
  • addElementToTopSteadyScroll 在不同浏览器中不一致(在 Edge 和 Chrome 上测试)。 addElementToTopFlowScroll 在浏览器中似乎是一致的,所以这可能是一个可能的修复。
  • @Niels 测试了 edge 和 chrome 并没有发现 addElementToTopSteadyScroll 有什么不同,你确定你使用的是 addElementToTopSteadyScroll 而不是 addElementToTop 吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 2011-08-09
  • 1970-01-01
  • 2012-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多