平滑背景图像的视差滚动

12

我做了一些研究,并编写了一个简单的jQuery代码,使得背景以略微不同的速度滚动,从而在向下滚动网站时创造出视差效果。

不幸的是,它有点卡顿。

这是HTML的基本布局:

<body>
    <section>
        Site content goes here.
    </section>
</body>

这是CSS代码:

body {
    background-image: url('../images/bg.png');
    background-repeat: repeat-y;
    background-position: 50% 0;    
}

这是JS代码:

$(window).scroll(function () {
    $("body").css("background-position","50% " + ($(this).scrollTop() / 2) + "px");
});

https://jsfiddle.net/JohnnyWalkerDesign/ksw5a0Lp/

很简单,但我的问题是当你滚动页面时,即使在一台强大的电脑上也有点卡顿。

有没有办法使背景视差动画流畅地运行?


2
嘿,看看这篇关于视差的博客文章:http://www.html5rocks.com/en/tutorials/speed/parallax/ - skndstry
6个回答

16
在你的CSS中添加转换属性,这样它就可以像这样通过GPU加速:
body {
    background-image: url('../images/bg.png');
    background-repeat: repeat-y;
    background-position: 50% 0;    
    transition: 0s linear;
    transition-property: background-position;
}

差别很小,但这就是我选择的。 - Chuck Le Butt
0秒?难道不应该是0.5秒吗? - Robo Robok
我不这么认为。那样做不会延迟效果吗?并且你想要的背景不会在滚动时稍微移动吗? - rosmcmahon

7
尝试使用浏览器支持的硬件加速属性进行动画处理。不要更改 background-position 属性,而是使用绝对定位的 img 元素,然后使用 CSS 变换来更改其位置。
看一下 stellar.js。该插件可以让你在支持 CSS 变换的浏览器中进行动画处理(stellar.js 还可以让你动画处理背景图像,但在移动设备上可能不太流畅)。它还利用了 requestAnimationFrame,这意味着 CPU、GPU 和内存的使用量更少。
如果你认为插件过于复杂,你至少可以查看所采用的方法并根据自己的需求进行调整。

5

将body的css设置如下:

body {
  background-image: url(images/bg.jpg); 
  background-repeat: no-repeat;
  background-attachment: fixed;
  background-position: 0 0;
 }

然后,在页面滚动时使用JavaScript获取pageYOffset,并将其设置为body背景图像的背景位置,如下所示:

window.addEventListener('scroll', doParallax);
function doParallax(){
   var positionY = window.pageYOffset/2;
   document.body.style.backgroundPosition = "0 -" + positionY + "px";
}

请看我的帖子: http://learnjavascripteasily.blogspot.in/

这里提供了一些简单易懂的JavaScript技术教程。


我正在尝试在一个类上使用这个代码:document.getElementsByClassName("parallax").style.backgroundPosition = "0 -" + positionY + "px"; 但它不起作用。有什么提示吗? - Rafael
1
document.getElementsByClassName("parallax")会给你一个dom元素数组。你不能直接在元素数组上使用'style'属性。因此,如果只有一个拥有'parallax'类的元素,请尝试使用'document.getElementsByClassName("parallax")[0].style.backgroundPosition'。 - Shwetha
好的。ShwethaU,谢谢。 - Rafael

2
有时候,由于某些原因,我们不能在 div 元素中使用 img 元素,比如 border-radius 可能会失效或者宽度大于父元素。我曾经遇到过这些问题,最好的解决方案是使用:
transition: 0.5s ease;
transform: translate3d(0, 0, 0);

我使用GPU获得了非常好的平滑视差效果。

看起来还不错。 - Chuck Le Butt

1
为了使其平滑,将图像放在一个单独的div中,并使用transform: translate来移动整个元素 - 这样你就会得到非常流畅的结果。
这里有一个小例子,做了一些稍微不同的事情,但是使用translate来给你一个想法:
HTML:
<div id="wrapper">
     <div id="content">Foreground content</div>
</div>

CSS:

@-webkit-keyframes MOVE-BG {
    0% {
        transform: translate(0%, 0%);
        -webkit-transform: translate(0%, 0%);
    }
    50% { 
        transform: translate(-250px, 0%);
        -webkit-transform: translate(-250px, 0%);
    }
    100% {
        transform: translate(0%, 0%);
        -webkit-transform: translate(0%, 0%);
    }
}

#wrapper {
    width: 300px;
    height: 368px;
    overflow: hidden;  
}
#content {
    width: 550px;
    height: 368px;
    background: url(http://www.gstatic.com/webp/gallery/1.jpg) 0% 0% repeat;
    text-align: center;
    font-size: 26px;
    color: #000;

    -webkit-animation-name: MOVE-BG;
    -webkit-animation-duration: 10s;
    -webkit-animation-timing-function: linear;
    -webkit-animation-iteration-count: infinite;
}

而且还有这个小工具:http://jsfiddle.net/piotku/kbqsLjfL/

如果要在JavaScript中(使用jQuery)实现,你需要使用类似以下的代码:

$(".element").css("transform", 'translateY(' + ($(this).scrollTop() / 2) + 'px)');

或者使用原生JS:

backgroundElement.style.transform = 'translateY(' + ($(this).scrollTop() / 2) + 'px)';

我认为这不会像你想象的那样有效。尝试将其放入一个fiddle中(不仅仅是你发布的转换),我认为你会发现它会表现得很奇怪。 - Chuck Le Butt
此外,过度使用前缀也是不必要的。现在最好避免使用它们,而是依靠 Autoprefixer。 - Chuck Le Butt
@Chuck Le Butt,答案中有一个小提琴链接 :) 你关于前缀的想法是正确的 - 我只是快速创建了一个可工作的示例。 - Picard
是的,正如我所说,你的fiddle链接并没有真正展示出解决问题的方法。它只是一个基本的转换,我不确定在视差情况下是否有效,但也许你可以在fiddle中演示一下。此外,我看到你已经从这个问题(https://dev59.com/IWEi5IYBdhLWcg3wpdnJ)中适应了代码,这可能就是为什么它有那么多怪癖的原因。感谢你的尝试。 - Chuck Le Butt
哎呀!我自己做了一个小工具,实际上它运行得非常好!https://jsfiddle.net/JohnnyWalkerDesign/ra90axjq/ - Chuck Le Butt

0
尝试将 .css 更改为 .animate。这样,您就可以将 CSS 设置为动画值,而不是硬编码的值。
$(window).scroll(function () {
    $("body").animate({"background-position":"50% " + ($(this).scrollTop() / 2) + "px"},{queue:false, duration:500});
});

注意:添加脚本http://snook.ca/technical/jquery-bg/jquery.bgpos.js

请记住我没有测试过它,如果可以,请告诉我。

动画背景图片:http://snook.ca/archives/javascript/jquery-bg-image-animations

演示:http://snook.ca/technical/jquery-bg/


2
一般而言,jQuery animate() 函数 不能用于 background-position 这样的多部分值。各自的 background-position-xbackground-position-y 样式没有得到标准化,并且似乎未被所有浏览器支持。 - Matt Coughlin
是的,一个视差网站在IE6中会如何运行?我可以想象不会很好。 - Marc Uberstein
1
background-position-xbackground-position-y在最新版本的Firefox和Opera中不受支持。它们已从CSS3规范中删除。目前尚不确定它们是否会出现在CSS4规范中。按照当前的编写方式,上述代码在任何浏览器中都无法正常工作。 - Matt Coughlin
谢谢提供信息!这个将不会得到任何支持吗? - Marc Uberstein
2
@MarcUberstein 哈!我不打算在这个时代支持IE6 :) - Chuck Le Butt
@DjangoReinhardt 记得添加脚本 http://snook.ca/technical/jquery-bg/jquery.bgpos.js - 请查看更新的答案。 - Marc Uberstein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接