我正在创建一个类似Chrome for Android地址栏的标题。结果是标题是一个伪的粘性标题,当你向下滚动时滚动出视图,然后你开始向后滚动标题滚动回视图。
现在它在桌面上工作正常(大约60fps)但在Chrome for Android(在Nexus 7 2013上)它充满了jank。
标题和内容区域都使用变换translateY移动,这比pos:top
更高效我也使用requestAnimationFrame去抖动滚动,只在最方便浏览器时更改属性。
标题为position: fixed; top: 0;
,然后使用transform: translateY(...);
滚动进出视图。此外,我使用transform: translateY(...);
我的js的基本结构如下:
var latestScrollTop = 0;
var lastReactedScrollTop = 0;
var ticking = false;
function DoScroll()
{
var builtUpScrollTop = latestScrollTop - lastReactedScrollTop;
// Fold the top bar while we are scrolling (lock it to scrolling)
$('header.main-header').css('transform', 'translateY(' ... 'px)');
HeaderHeightChange();
lastReactedScrollTop = latestScrollTop;
ticking = false;
}
function HeaderHeightChange()
{
// We need to update the margin-top for the content so we don't overlap it
$('main.content-area').css('transform', 'translateY(' ... 'px)');
}
function requestTick() {
if(!ticking) {
requestAnimationFrame(function(){
DoScroll();
});
}
ticking = true;
}
$(window).on('scroll', function(e) {
latestScrollTop = $(window).scrollTop();
requestTick();
});
效果不完整,因为它需要在完成滚动(并编码)后解决折叠,但我不想在只有滚动移动锁定到标题导致jank时使问题复杂化。我在上下滚动时看到绘制矩形,即使我正在改变变换,我认为gpu正在处理,不应该绘画。
编辑:在使用ADB进行调试时,似乎每帧中都有一堆清晰的灰色轮廓时间。
答案 0 :(得分:1)
事实证明,即使我使用的是transform: translateY()
,您仍然需要添加translateZ(0)
才能看到图层的好处并加速gpu。
但是我也更新了我的代码以使用对象文字代码样式,并通过阅读然后编写来消除时间轴中的forced synchronous layout
警告。这与requestAnimationFrame
结合在一起。
var myUtils = {
clamp: function(min, max, value) {
return Math.min(Math.max(value, min), max);
},
getTranslateYFromTransform: function(rawTransform) {
return parseFloat(rawTransform.match(/^matrix\((([+-]?[0-9]*\.?[0-9]*),\s*?){5}([+-]?[0-9]*\.?[0-9]*)\)$/)[3])
}
};
var scrollHeader = {
latestScrollTop: 0,
lastReactedScrollTop: 0,
headerHeight: 0,
headerTransformTranslateY: 0,
ticking: false,
requestTick: function() {
if(!scrollHeader.ticking) {
requestAnimationFrame(function(){
scrollHeader.doHeaderFold();
});
}
scrollHeader.ticking = true;
},
doHeaderFold: function() {
var header = $('header.main-header');
var builtUpScrollTop = scrollHeader.latestScrollTop - scrollHeader.lastReactedScrollTop;
scrollHeader.headerHeight = header.outerHeight();
scrollHeader.headerTransformTranslateY = myUtils.clamp(-parseInt(scrollHeader.headerHeight), 0, (myUtils.getTranslateYFromTransform(header.css('transform')) - builtUpScrollTop));
// Fold the top bar while we are scrolling (lock it to scrolling)
header.css('transform', 'translateY(' + scrollHeader.headerTransformTranslateY + 'px) translateZ(0)');
scrollHeader.headerHeightChange();
scrollHeader.lastReactedScrollTop = scrollHeader.latestScrollTop;
scrollHeader.ticking = false;
},
headerHeightChange: function() {
// We need to update the margin-top for the content so we don't overlap it
$('main.content-area').css('transform', 'translateY(' + (scrollHeader.headerHeight + scrollHeader.headerTransformTranslateY) + 'px) translateZ(0)');
}
};
$(window).on('scroll', function(e) {
//console.log(e);
scrollHeader.latestScrollTop = $(window).scrollTop();
scrollHeader.requestTick();
});
这使得ADB(Nexus 7 2013)上的时间轴调试看起来像(非常流畅):
在第一次滚动时,为了摆脱小跳跃,在动画制作之前将transform: translateZ(0)
添加到元素中。