getBoundingClientRect()在Safari浏览器中无法正常工作求助
Safari中
getBoundingClientRect()滚动定位失效的问题与解决 我最近碰到了个头疼的兼容性问题:在菜单功能里用getBoundingClientRect()实现滚动定位,在iPhone上的Chrome、Firefox浏览器都能正常平滑滚动到目标区域,但在Safari里完全没反应。先给大家看看我最初的代码:
初始代码
HTML结构
<div class="menuDiv" id="menuDivId"> <div class="menu" id="menuId"> <ul> <li> <div class="borderBo"> <a class="active" id="booking" href="#book">Booking</a> </div> </li> </ul> </div> </div> <div> . . . lots of text . . . . </div> <div class="bookings" id="bookingScroll"> </div> <div> . . . lots of text . . . . </div>
JavaScript代码
var bookingScroll = document.getElementById("bookingScroll"); document.getElementById('booking').addEventListener('click', function(){ window.scrollTo({ top: bookingScroll.getBoundingClientRect().top, behavior: "smooth" }); })
问题原因
后来我琢磨明白,问题出在坐标系统的差异上:getBoundingClientRect().top返回的是目标元素相对于当前视口顶部的距离,而window.scrollTo()的top参数要求的是相对于文档顶部的距离。Chrome等浏览器会自动处理这个转换,但Safari对坐标的处理更严格,直接用视口距离作为滚动目标就会导致定位错误。
原生JS修复方案
要解决这个问题,只需要把视口距离加上当前页面已经滚动的距离就行。我们可以用window.pageYOffset(或者兼容性更好的document.documentElement.scrollTop)来获取已滚动的距离,修改后的代码如下:
var bookingScroll = document.getElementById("bookingScroll"); document.getElementById('booking').addEventListener('click', function(){ // 获取元素相对于视口的顶部距离 const rectTop = bookingScroll.getBoundingClientRect().top; // 获取当前页面已滚动的垂直距离 const currentScrollTop = window.pageYOffset || document.documentElement.scrollTop; // 计算文档顶部的目标位置 window.scrollTo({ top: rectTop + currentScrollTop, behavior: "smooth" }); })
jQuery替代方案
我自己也找到了基于jQuery的解决方案,这个方法在Safari里也能正常工作,原理是jQuery的offset().top直接返回元素相对于文档顶部的距离,不需要手动转换:
$('#booking').on('click', function() { $('html, body').animate({ scrollTop: $('#bookingScroll').offset().top }, 'smooth'); });
总之,核心就是要区分视口坐标和文档坐标,Safari不会帮我们自动转换,所以手动补上已滚动距离就能解决问题啦。
内容的提问来源于stack exchange,提问作者Deke
相关产品推荐
相关产品推荐

