iOS Safari浏览器下平滑滚动offset偏移量不生效问题求助
iOS Safari锚点滚动偏移异常修复方案
你遇到的问题是iOS Safari特有的几个交互逻辑和标准浏览器不一致导致的,核心问题和修复方法如下:
核心问题原因
- 你代码中动画结束后的
focus()操作会触发浏览器默认的聚焦滚动行为:浏览器会强制将聚焦元素对齐到视口顶部,直接覆盖你之前计算好的带偏移的滚动位置,iOS Safari对该行为的触发优先级远高于其他桌面浏览器 - 同时给
html, body两个元素加滚动动画会在iOS Safari中触发两次动画执行,导致滚动位置计算被覆盖 - 部分iOS版本中Safari的地址栏、底部工具栏高度会动态变化,导致点击时计算的
offset().top和实际滚动时的布局偏移不一致 - 缺少动画队列清空逻辑,如果用户连续点击多个锚点,动画队列叠加会导致最终偏移错误
修复后代码
// Select all links with hashes $('a[href*="#"]') // Remove links that don't actually link to anything .not('[href="#"]') .not('[href="#0"]') .click(function(event) { // On-page links if ( location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname ) { // Figure out element to scroll to var offset = 0; var target = $(this.hash); target = target.length ? target : $('[name=' + this.hash.slice(1) + ']'); if ($(this).data('offset') != undefined) offset = $(this).data('offset'); // Does a scroll target exist? if (target.length) { // Only prevent default if animation is actually gonna happen event.preventDefault(); // 清空之前的滚动动画队列,避免叠加 $('html, body').stop(); // 滚动前重新计算偏移,避免布局变化导致的计算错误 var targetScrollTop = target.offset().top - offset; $('html, body').animate({ scrollTop: targetScrollTop }, 1000, function() { // Callback after animation // Must change focus! var $target = $(target); // 聚焦时禁止浏览器默认滚动,避免覆盖偏移 $target.focus({preventScroll: true}); if (!$target.is(":focus")) { $target.attr('tabindex','-1'); // 非可聚焦元素同样加禁止滚动参数 $target.focus({preventScroll: true}); }; // 兼容低版本iOS Safari,兜底修正滚动位置 if (window.pageYOffset !== targetScrollTop) { window.scrollTo(0, targetScrollTop); } }); } } });
额外适配检查项
- 如果你的移动端导航栏点击后会收起,需要监听导航栏的过渡动画结束事件后再执行滚动计算,避免收起过程中布局高度变化导致偏移错误
- 检查css中是否给
html或body设置了overflow-x: hidden,该属性会导致iOS Safari滚动容器识别错误,建议将该属性移到页面最外层的容器元素上 - 低于iOS 15的设备不支持
preventScroll参数,可以把focus逻辑移到滚动动画执行之前,避免触发滚动
内容的提问来源于stack exchange,提问作者Erikamyself
相关产品推荐
相关产品推荐

