阻止浏览器滚动HTML5历史记录popstate

Ale*_*ret 78 html javascript browser-history dom-events

当popstate事件发生时,是否可以阻止滚动文档的默认行为?

我们的网站使用jQuery动画滚动和History.js,状态更改应该将用户滚动到页面的不同区域,无论是通过pushstate还是popstate.问题是浏览器在发生popstate事件时自动恢复先前状态的滚动位置.

我已经尝试使用容器元素设置为文档的100%宽度和高度,并滚动该容器内的内容.我发现的问题是它似乎没有滚动文档那么顺畅; 特别是如果使用大量的css3,如盒阴影和渐变.

我还尝试在用户启动的滚动期间存储文档的滚动位置,并在浏览器滚动页面后(在popstate上)恢复它.这在Firefox 12中运行良好,但在Chrome 19中,由于页面正在滚动和恢复,因此存在闪烁.我假设这与滚动和被触发的滚动事件之间的延迟有关(滚动位置被恢复的地方).

Firefox在popstate触发之前滚动页面(并触发滚动事件),Chrome首先触发popstate然后滚动文档.

我见过的所有使用历史API的网站都使用与上述类似的解决方案,或者只是在用户返回/转发时忽略滚动位置更改(例如GitHub).

是否可以阻止文档在popstate事件中滚动?

Tam*_*ári 59

if ('scrollRestoration' in history) {
  history.scrollRestoration = 'manual';
}
Run Code Online (Sandbox Code Playgroud)

(谷歌于2015年9月2日公布)

浏览器支持:

Chrome:支持(自46起)

Firefox:支持(自46起)

IE/Edge:不支持,请求支持(然后在评论中留下链接)

Opera:支持(自33年起)

Safari:支持

有关详细信息,请参阅MDN上的浏览器兼容性.


Bea*_*rtz 31

这已成为mozilla开发人员核心一年多来报道的问题.不幸的是,机票并没有真正进步.我认为Chrome是一样的:没有可靠的方法onpopstate通过js 解决滚动位置,因为它是本机浏览器行为.

但是,如果你看一下HTML5历史规范,它明确希望在状态对象上表示滚动位置,那么对未来充满希望:

历史对象将其浏览上下文的会话历史记录表示为会话历史记录条目的平面列表.每个会话历史条目包括URL和可选的状态对象,并且还可以具有标题,文档对象,表单数据,滚动位置以及与其相关联的其他信息.

这一点,如果你阅读上面提到的关于mozilla票证的评论,就会给出一些迹象,表明在不久的将来可能不会再恢复滚动位置onpopstate,至少对于使用的人来说pushState.

不幸的是,在此之前,滚动位置在pushState使用时被存储,并且replaceState不会替换滚动位置.否则,它会相当容易,并且您可以使用replaceState每次用户滚动页面时设置当前的Scroll位置(使用一些谨慎的onscroll处理程序).

同样不幸的是,HTML5规范并未指定何时popstate必须触发事件,它只是说:"在某些情况下导航到会话历史记录条目时会被触发",这不清楚地说明它是在之前还是之后; 如果它总是在之前,可以在popstate之后处理滚动事件的解决方案.

取消滚动事件?

此外,如果滚动事件是可取消的,那么它也很容易,但事实并非如此.如果是,你可以取消一系列的第一个滚动事件(用户滚动事件就像旅鼠,它们有几十个,而历史重新定位触发的滚动事件是一个),你会没事的.

现在还没有解决方案

据我所知,我现在唯一推荐的就是等待HTML5规范完全实现,并在这种情况下使用浏览器行为滚动,这意味着:当浏览器允许你滚动时动画滚动,并在有历史事件时让浏览器重新定位页面.您可以影响位置的唯一方法是,pushState当页面以良好的方式定位时,您可以使用它.任何其他解决方案要么有错误,要么特定于浏览器,或两者兼而有之.