Javascript 改变卷轴上的CSS变换:快速移动与平滑移动

Javascript 改变卷轴上的CSS变换:快速移动与平滑移动,javascript,css,performance,scroll,parallax,Javascript,Css,Performance,Scroll,Parallax,我对现有的视差库不满意,所以我试着写我自己的。我目前的课程包括三个主要课程: ScrollDetector跟踪元素相对于屏幕的滚动位置;它具有返回代表其当前位置的浮点值的功能: 0表示元素的上边缘位于视口的下边缘 1表示位于视口顶部边缘的元素的底部边缘 所有其他位置都是线性插值/外推的 ScrollAnimation使用ScrollDetector实例根据ScrollDetector元素在另一个元素上插入任意CSS值 ParallaxativeAnimation扩展了ScrollAnima

我对现有的视差库不满意,所以我试着写我自己的。我目前的课程包括三个主要课程:

  • ScrollDetector
    跟踪元素相对于屏幕的滚动位置;它具有返回代表其当前位置的浮点值的功能:
    • 0
      表示元素的上边缘位于视口的下边缘
    • 1
      表示位于视口顶部边缘的元素的底部边缘
    • 所有其他位置都是线性插值/外推的
  • ScrollAnimation
    使用
    ScrollDetector
    实例根据
    ScrollDetector
    元素在另一个元素上插入任意CSS值
  • ParallaxativeAnimation
    扩展了
    ScrollAnimation
    ,用于背景图像的特殊情况,背景图像应以窗口滚动速度的精确因数滚动
我目前的情况是:

  • 滚动动画
    s使用
    变换:translateY(x)
    工作平稳
  • ParallaxativeAnimation
    s使用
    translateY(x)
    工作,但动画制作不平稳
  • ParallaxativeAnimation
    s使用
    translate3d(0,x,0)
    是不稳定的,但没有那么严重
  • 该库的动画使用
    translate3d(0,x,0)
    ,工作非常顺利
你可以看到比较。(这种冲动在Firefox中表现得最好。)我的库是

我不知道我的图书馆里的问题在哪里,我也不知道如何解决它。下面是一个简略的粘贴,在
ScrollAnimation
类中滚动时完成了举重,该类工作平稳:

getCSSValue(set, scrollPosition) {
    return set.valueFormat.replace(set.substitutionString, ((set.endValue - set.startValue) * scrollPosition + set.startValue).toString() + set.unit)
}

updateCSS() {
    var cssValues = [];

    var scrollPosition = this.scrollDetector.clampedRelativeScrollPosition();

    var length = this.valueSets.length;
    for(var i = 0; i < length; i++) {
        cssValues.push(getCSSValue(valueSets[i], scrollPosition) );
    }

    this.setCSS(cssValues);
    this.ticking = false;
}

requestUpdate() {
    if(!this.ticking) {
        requestAnimationFrame(() => { this.updateCSS(); });
    }

    this.ticking = true;
}
数学似乎并不复杂,所以我不知道这是如何影响动画性能的。我认为区别可能在于我在视差图像上的样式,但在上面的画笔中,Rellax版本有完全相同的CSS,但动画非常流畅。Rellax似乎正在对每一帧进行更复杂的计算:

var updatePosition = function(percentage, speed) {
  var value = (speed * (100 * (1 - percentage)));
  return self.options.round ? Math.round(value) : Math.round(value * 100) / 100;
};


//
var update = function() {
  if (setPosition() && pause === false) {
    animate();
  }

  // loop again
  loop(update);
};

// Transform3d on parallax element
var animate = function() {
  for (var i = 0; i < self.elems.length; i++){
    var percentage = ((posY - blocks[i].top + screenY) / (blocks[i].height + screenY));

    // Subtracting initialize value, so element stays in same spot as HTML
    var position = updatePosition(percentage, blocks[i].speed) - blocks[i].base;

    var zindex = blocks[i].zindex;

    // Move that element
    // (Set the new translation and append initial inline transforms.)
    var translate = 'translate3d(0,' + position + 'px,' + zindex + 'px) ' + blocks[i].transform;
    self.elems[i].style[transformProp] = translate;
  }
  self.options.callback(position);
};
var updatePosition=函数(百分比、速度){
var值=(速度*(100*(1-百分比));
返回self.options.round?Math.round(值):Math.round(值*100)/100;
};
//
var update=函数(){
if(setPosition()&&pause==false){
制作动画();
}
//再次循环
循环(更新);
};
//基于视差元素的三维变换
var animate=函数(){
对于(变量i=0;i
从Chrome开发者工具中我能真正分辨出的唯一一件事是帧速率没有下降到60 fps以下太多,所以也许不是我在每帧上做了太多的工作,而是我在计算位置时做了一些数学上不正确的事情

所以我不知道。很明显,我在这里有点不知所措。我很抱歉把整个库扔向StackOverflow并说“修复它”,但如果有人能告诉我我做错了什么,或者告诉我如何使用开发工具来找出我做错了什么,我将非常感激


编辑
好的,我已经计算出了滚动抖动的最重要因素是被转换元素的高度。当我的
ScrollPixelsPerParallaxixel
属性较高时,我的库中出现了一个计算错误,导致背景图像比需要的高出很多。我现在正在尝试纠正这个问题。

除了计算之外,您还可以尝试使用Promise异步运行它:

await Promise.all([
  loop(update);
]);
只是看看它是否对性能有积极影响


我愿意发表评论,但我还没有足够的声誉。

您希望避免触摸DOM或更改屏幕上的任何内容通过在元素上实现,您可以获得视觉性能提升。它在中受支持(不包括边缘和无IE)

CSS属性将向浏览器提示元素的预期更改方式。浏览器可能会在实际更改元素之前设置优化。这些类型的优化可以通过在实际需要之前做一些可能非常昂贵的工作来提高页面的响应能力

你可以像这样推动它:

function gogoJuice() {
  // The optimizable properties that are going to change
  self.elems[i].style.willChange = 'transform';
}

function sleepNow() {
  self.elems[i].style.willChange = 'auto';
}
或者更基本地说,只是在您正在更改的元素上的css中:

.parallax {
  will-change: transform;
}
此属性旨在作为作者让用户代理知道可能提前更改的属性的方法。然后,浏览器可以选择在属性更改实际发生之前提前应用属性更改所需的任何优化。因此,给浏览器一些时间来实际进行优化是很重要的。找到一些方法,至少提前一点预测某些事情会发生变化,然后设定会发生变化


两件事:要公平地比较库的两个版本,您应该将它们应用于相同的元素。将标题的滚动性能与大背景图像的滚动性能进行比较是不公平的。我希望看到两个版本都在背景图像上运行。其次,我注意到Rellax对滚动元素应用了
translate3d()
转换,而您应用了
translateY()
。这可能
.parallax {
  will-change: transform;
}