将滚动条 div 同步到非滚动的 div



我有一个网页,里面有三个同步的div。

+----------+
|   TOP    |
+---+----------+
|   |         ||
| L | CENTER  ||
|   |_________||
+---+----------+
<!--Rough HTML-->
<div>
<div class="topbar-wrapper">
<div class="topbar"></div>
</div>
<div class="container">
<div class="sidebar-wrapper">
<div class="sidebar"></div>
</div>
<div class="center-wrapper"> <!-- Set to the window size & overflow:scroll -->
<div class="center"></div> <!-- Has the content -->
</div>
</div>
</div>

中心div 具有水平和垂直滚动条。顶部和左侧div 没有滚动条。相反,当水平滚动条移动时,滚动事件会相应地更新顶部div 的margin-left。同样,当移动垂直滚动条时,margin-top也会更新。在这两种情况下,它们都设置为负值。

$('.center-wrapper').scroll(function(e) {
$('.sidebar').css({marginTop: -1 * $(this).scrollTop()});
$('.topbar').css({marginLeft: -1 * $(this).scrollLeft()});
});

这在Chrome和Firefox中工作正常。但在 Safari 中,移动滚动条和正确设置负边距之间存在延迟。

有没有更好的方法可以做到这一点?或者有没有办法摆脱 Safari 的滞后?

编辑:

看看这个小提琴,看看Safari的滞后:http://jsfiddle.net/qh2K3/

让我知道这个JSFiddle是否更好用。 我也经历了同样的"滞后"(OS X 上的 Safari 7),这些小的 CSS 更改显着改善了它。 我最好的猜测是Safari很懒惰,没有打开其高性能电机。 我们可以强制 Safari 使用一些简单的 CSS 打开它:

.topbar-wrapper, .sidebar-wrapper, .center-wrapper {
-webkit-transform: translateZ(0);
-webkit-backface-visibility: hidden;
-webkit-perspective: 1000;
}

这样可以通过将一些工作卸载到 GPU 来实现 Safari 中的硬件加速 CSS。 它改进了浏览器中的渲染,这可能是延迟的问题。

我遇到过几次这个问题,在基于此类事件增量移动元素时,野生动物园似乎滞后了。

以下是我过去解决问题的方法。

在支持硬件加速的浏览器中,使用任何"3d"CSS 属性都将启用硬件加速。

如果支持 3D 变换,我们不妨使用 translate3d 来移动元素,因为这比移动像素更平滑。

这意味着我们首先必须找出 CSS 转换属性的正确前缀,然后检查对 3D 转换的支持。如果我们有支持,请平移元素,如果不是移动像素。

通过找出没有库的前缀和 3D 支持,它应该尽可能快,并且没有依赖关系。

var parent     = document.querySelector('.center-wrapper'),
sidebar    = document.querySelector('.sidebar'),
topbar     = document.querySelector('.topbar'),
has3D      = false,
transform  = null,
transforms = {
'webkitTransform' : '-webkit-transform',
'OTransform'      : '-o-transform',
'msTransform'     : '-ms-transform',
'MozTransform'    : '-moz-transform',
'transform'       : 'transform'
};
for (var k in transforms) if (k in parent.style) transform = k;
if ( transform !== null ) {
sidebar.style[transform] = 'translate3d(0,0,0)'; // start hardware acc
topbar.style[transform]  = 'translate3d(0,0,0)'; // start hardware acc
// check support
var s = window.getComputedStyle(sidebar).getPropertyValue(transforms[transform]);
has3D = s !== undefined && s.length > 0 && s !== "none";
}
if (has3D) {
parent.onscroll = function (e) {
sidebar.style[transform] = 'translate3d(0px, '+ (this.scrollTop * -1) +'px, 0px)';
topbar.style[transform]  = 'translate3d('+ (this.scrollLeft * -1) +'px, 0px, 0px)';
}
}else{
parent.onscroll = function (e) {
sidebar.style.marginTop = (this.scrollTop  * -1) + 'px';
topbar.style.marginLeft = (this.scrollLeft * -1) + 'px';
}
}

小提琴

请记住将其放在 DOM 中的元素之后,就像在</body>之前一样,或者如果这是不可能的,则必须将其包装在 DOM 就绪处理程序中。

作为旁注,IE7及更低版本不支持querySelector,如果这是一个问题,您必须填充它。

缓存选择器会有所帮助。

改变:

$('.center-wrapper').scroll(function(e) {
$('.sidebar').css({marginTop: -1 * $(this).scrollTop()});
$('.topbar').css({marginLeft: -1 * $(this).scrollLeft()});
});

自:

var _scroller = $('.center-wrapper'),
_swrapper = $('.sidebar-wrapper'),
_twrapper = $('.topbar-wrapper');
_scroller.scroll(function (e) {
_swrapper.scrollTop(_scroller.scrollTop());
_twrapper.scrollLeft(_scroller.scrollLeft());
});

如果.scroll()每次都必须重新创建 jquery 对象$(this),它将非常努力。

昨晚在评论中写了这篇文章,虽然还无法测试,但实际上今天觉得应该添加这与性能直接相关。

我们可以尝试一下 -这里


更多/方法 - 使它们也成为本地人

我们也可以删除另一个jquery方法调用。 通过缓存和返回本机_scrollernative = _scroller.get(0).scrollTop().scrollLeft(),以利用现成的属性scrollLeft

喜欢:

var _scroller = $('.center-wrapper'),
_scrollernative = _scroller.get(0),
_swrapper = $('.sidebar-wrapper').get(0),
_twrapper = $('.topbar-wrapper').get(0);
_scroller.scroll(function (e) {
_swrapper.scrollTop = _scrollernative.scrollTop;
_twrapper.scrollLeft = _scrollernative.scrollLeft;
});

我们可以在这里尝试一下



我很欣赏您的代码可能会在页面上查看多个这些控件,这就是为什么您使用类并需要查找S(this)而不是使用 ID 的原因。

为此,我仍然会使用上述缓存方法,但在此之前我们需要一一创建它们。(在我们初始化每个实例的 scroll() 函数之前缓存)

(function() {
var _scroller = $('.center-wrapper'),
_swrapper = $('.sidebar-wrapper').get(0),
_twrapper = $('.topbar-wrapper').get(0);
function setScrollers(_thisscroller) {
_scrollernative = _thisscroller.get(0);
/* start the scroll listener per this event */
_thisscroller.scroll(function (e) {
_swrapper.scrollTop = _scrollernative.scrollTop;
_twrapper.scrollLeft = _scrollernative.scrollLeft;
}); 
}
_scroller.each(function() { setScrollers($(this)); });
})();

我们可以在这里尝试一下


但是正如我所看到的.sidebar-wrapper和.topbar-wrapper是独一无二的,mabye .center-wrapper也是独一无二的。

那么最终对这些元素使用 id 来缩短所有内容怎么样?

var _scroller = document.getElementById('center-wrapper'),
_swrapper = document.getElementById('sidebar-wrapper'),
_twrapper = document.getElementById('topbar-wrapper');
_scroller.onscroll = function() {
_swrapper.scrollTop = _scroller.scrollTop;
_twrapper.scrollLeft = _scroller.scrollLeft;
}; 

我们可以在这里尝试一下


与其使用marginTop & marginLeft来更改.sidebar & .topbar的边距,不如使用scrollTop & scrollLeft来表示溢出的div.sidebar-wrapper & .topbar-wrapper,看看它现在是否可以在Safari中工作:

演示小提琴

$('.center-wrapper').scroll(function(e) {
$('.sidebar-wrapper').scrollTop($(this).scrollTop());
$('.topbar-wrapper').scrollLeft($(this).scrollLeft());
});

试试这个小提琴,让它在野生动物园中看起来最好,经过测试

最新更新