浏览器F5刷新保留滚动位置问题测试与异常分析
F5刷新后浏览器保留滚动位置,onload中scrollTo无效的原因及解决办法
现象总结
- 测试环境:仅加载一张大图片的HTML页面,四款浏览器测试结果:
- Chrome、Opera、Edge(Chromium内核):F5刷新后会保留之前的页面滚动位置
- Firefox:F5刷新后自动回到页面顶部
- 在
<body.onload>中调用scrollTo(0,0),日志显示scrollY临时变为0,但页面并未回到顶部;5秒后异步执行的函数中scrollY恢复为刷新前的数值。
原因分析
Chromium内核浏览器(Chrome、Edge、Opera)自带自动滚动恢复机制:当用户刷新页面时,浏览器会在页面加载流程的后期(onload事件执行之后)自动将页面滚动到刷新前的位置。你在onload里调用scrollTo(0,0)虽然临时修改了滚动位置,但后续浏览器的自动恢复操作会覆盖这个设置,导致页面最终回到原来的滚动位置,scrollY也随之恢复。
解决方案
方案1:禁用浏览器自动滚动恢复(推荐)
使用标准API history.scrollRestoration,直接阻止浏览器的滚动恢复行为,修改后的代码如下:
<!DOCTYPE html> <html lang="en-us"> <head> <title>Scroll Test</title> <meta charset="UTF-8"> <script> // 禁用自动滚动恢复 history.scrollRestoration = "manual"; function showScrollY() { return " " + `scrollY=${scrollY}, ` + `this.scrollY=${this.scrollY}, ` + `window.scrollY=${window.scrollY}` ; } function theOnLoad() { console.log( "* From <body.onload>\n" + " - Before scrollTo( 0, 0)\n" + showScrollY() ); scrollTo( 0, 0 ); console.log( " - After scrollTo( 0, 0 )\n" + showScrollY() ); setTimeout( theTimeout, 5000 ); } function theTimeout() { console.log( "* From theTimeout() after 5 seconds\n" + showScrollY() ); } </script> </head> <body onload="theOnLoad(); "> <img src="https://upload.wikimedia.org/wikipedia/commons/0/0f/Homepage_of_Wikipedia.png" alt="Homepage of Wikipedia"> </body> </html>
设置history.scrollRestoration = "manual"后,浏览器不会自动恢复滚动位置,onload中的scrollTo(0,0)会生效,页面刷新后停在顶部。
方案2:在浏览器滚动恢复完成后执行scrollTo
如果需要兼容不支持history.scrollRestoration的旧浏览器,可以监听pageshow事件(该事件在页面加载完成,包括浏览器完成滚动恢复后触发),或者用setTimeout延迟执行scrollTo:
// 监听pageshow事件 window.addEventListener('pageshow', function() { window.scrollTo(0, 0); });
或者修改onload中的逻辑,延迟执行scrollTo:
function theOnLoad() { console.log( "* From <body.onload>\n" + " - Before scrollTo( 0, 0)\n" + showScrollY() ); // 延迟100ms执行,确保在浏览器滚动恢复之后 setTimeout(() => { window.scrollTo(0, 0); console.log( " - After scrollTo( 0, 0 )\n" + showScrollY() ); }, 100); setTimeout( theTimeout, 5000 ); }
原始测试代码与日志
测试代码
<!DOCTYPE html> <html lang="en-us"> <head> <title>Scroll Test</title> <meta charset="UTF-8"> <script> function showScrollY() { return " " + `scrollY=${scrollY}, ` + `this.scrollY=${this.scrollY}, ` + `window.scrollY=${window.scrollY}` ; } function theOnLoad() { console.log( "* From <body.onload>\n" + " - Before scrollTo( 0, 0)\n" + showScrollY() ); scrollTo( 0, 0 ); console.log( " - After scrollTo( 0, 0 )\n" + showScrollY() ); setTimeout( theTimeout, 5000 ); } function theTimeout() { console.log( "* From theTimeout() after 5 seconds\n" + showScrollY() ); } </script> </head> <body onload="theOnLoad(); "> <img src="https://upload.wikimedia.org/wikipedia/commons/0/0f/Homepage_of_Wikipedia.png" alt="Homepage of Wikipedia"> </body> </html>
控制台日志
test.html:14 * From <body.onload> - Before scrollTo( 0, 0) scrollY=928, this.scrollY=928, window.scrollY=928 test.html:18 - After scrollTo( 0, 0 ) scrollY=0, this.scrollY=0, window.scrollY=0 test.html:23 * From theTimeout() after 5 seconds scrollY=928, this.scrollY=928, window.scrollY=928
内容的提问来源于stack exchange,提问作者John Berenberg
相关产品推荐
相关产品推荐

