我有一个网页,里面有三个同步的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());
});