关于jQuery背景更改的闪烁

时间:2013-04-24 00:31:25

标签: javascript jquery css preload

我为我当前的代码创建了一个jsfiddle。 http://jsfiddle.net/gL5sB/38/

我正在尝试更改滚动事件的正文背景css。当背景改变时,当更新css并加载新图像时,它似乎闪烁。有时看起来很顺利然后似乎变得更糟。很奇怪。好奇,如果有人知道如何优化?

我正在预装图片。不知道闪烁的原因。有什么想法吗?

$(document).ready(function () {
    switchImage();
});

$(window).scroll(function () {
    switchImage();
});

var pics = []; // CREATE PICS ARRAY

//PRELOAD FUNCTION TO SET UP PICS ARRAY IN MEMORY USING IMAGE OBJECT
function preload() {
    for (i = 0; i < arguments.length; i++) {
        pics[i] = new Image();
        pics[i].src = arguments[i];
        //alert("preload " + arguments[i]);
    }
}
preload(
    'bgImage/100.jpg',
    'bgImage/101.jpg',
    'bgImage/102.jpg',
    'bgImage/103.jpg',
    'bgImage/104.jpg',
    'bgImage/105.jpg',
    'bgImage/106.jpg',
    'bgImage/107.jpg',
    'bgImage/108.jpg',
    'bgImage/109.jpg',
    'bgImage/110.jpg',
    'bgImage/111.jpg',
    'bgImage/112.jpg',
    'bgImage/113.jpg'
);

function switchImage() {
    var s = $(window).scrollTop()/10;
    var index = Math.floor(s / 5);

    $('body').css('background-image', 'url(' + pics[index].src + ')');
}

4 个答案:

答案 0 :(得分:3)

为什么不使用一个图像(精灵图像)并仅使用background-position移动它而不是替换图像? (关于尺寸 - 您可以根据情况设置background-size的百分比 - 高度为1400%

因为你无论如何都要预加载所有图像 - 它不会花费你的页面加载时间 - 它也可能节省一些时间,因为正确的压缩1图像14将重量少于14图像1

答案 1 :(得分:2)

Chrome也行。我可以看到IE中的闪烁。解决方案就在这篇文章的底部。

我怀疑视频版本会压缩和加载比所有图像更快,但正如@Allendar绘制的那样,它将是最有效的传输。我建议使用canvas或SVG。

使用图像的另一种方法是将单个组件作为图像或图标字体放置在显示器上,并进行绝对定位,然后在脚本中打开或关闭它们。但这是一个非常复杂的解决方案。

我认为现在解决问题的最简单,最快捷的方法就是调整你的解决方案。正如其他人所建议的那样,多图像方法不会超级高效,如果您打算采用该路线,至少要确保将Web服务器上的缓存标头设置为无限期缓存;

Cache-Control: public;
Expires: Mon, 31 Dec 2035 12:00:00 GMT

好的,所以闪烁问题只是IE中渲染引擎的一个错误/效率低下的问题,所以这是一种使用不同方法的解决方法。

基本上将DIV放在body上,而不是使用body本身。事实上,在这种情况下,我们使用多个DIV s,每个图像一个,并将它们叠加在一起。您也可以在脚本中创建这些节点。

其次,为您的内容添加另一个DIV,并将其覆盖在body上;

<body>
    <div id="b100" class="background" style="background-image:url('http://ingodwetrustthemovie.com/bgImage/100.jpg')"></div>
    <!-- rest omitted -->
    <div id="b113" class="background" style="background-image:url('http://ingodwetrustthemovie.com/bgImage/113.jpg')"></div>
    <div id="content">
        <div id="test">test div</div>
        here is some text
    </div>
</body>

一次只显示一个并隐藏其余部分;

function switchImage() {
    var s = $(window).scrollTop()/10;
    var index = Math.floor(s / 5);

    $('.background').hide();
    $('.background').eq(index).show();
}

我怀疑twssdling css display选项会比改变src属性更少,而且似乎可以解决这个问题。

这是Fiddle

当然,您可能仍需要优化代码以允许首先显示第一个加载的图像而不是普通背景,但我认为这证明了修复的原则。

您还可以考虑制作一个非常大的CSS Sprite,方法是将图像捆绑成一个巨大的条带,然后使用background-position。那可能会对body标签本身起作用。当然这意味着在你可以显示任何图像之前下载一个巨大的文件,但有两个好处;

  1. 一张图像(尤其是具有这种相似性的图像)将比单独的图像压缩方式更好。
  2. 使用相同的缓存指令,这是第一次获取图像时只有一个HTTP / GET / 302周期而不是13周期,因此您的页面加载速度可能会更快。
  3. SVG

    SVG元素的工作方式与DOM类似。如果您可以将您的内容作为SVG提供,您可以深入查看图形,找到元素,给它们ID等,并像操纵任何其他DOM元素一样操纵它们;

    <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
       <ellipse id="e1" cy="420" cx="200" rx="420" ry="30" style="fill:3f5566" />
       <ellipse id="e2" cy="420" cx="170" rx="390" ry="20" style="fill:4f5566" />
       <ellipse id="e3" cy="420" cx="145" rx="370" ry="15" style="fill:5f5566" />
       <ellipse id="e4" cy="420" cx="100" rx="370" ry="20" style="fill:6f5566" />
       <ellipse id="e5" cy="420" cx="45"  rx="300" ry="15" style="fill:8f5566" />
    </svg>
    

    这是另一个基于滚动隐藏/取消隐藏SVG元素的fiddle

    理想情况下,假设他们已经在“图层”中生成了该图形,请尝试让设计人员为您提供一个SVG,其中图层将转换为groups。例如,Adobe Illustrator可以do that

    然后,您可以根据需要轻松关闭图层/组以创建动画效果。

答案 2 :(得分:2)

如果不需要图像,您可以自己创建一些系统,并使用画布继续更新背景。这将是开始;

JSfiddle

<强> HTML

<img id="template" src="http://ingodwetrustthemovie.com/bgImage/100.jpg" />
<canvas id="absBg" width="1000px" height="560px"></canvas>

<强> CSS

body {
    margin: 0px;
}

#template {
    position: absolute;
    width: 1000px;
    height: 563px;
}

#absBg {
    position: absolute;
    /*background: rgba(0, 0, 0, 0.50);*/
    /*height: 100%;*/
}

<强>的JavaScript / jQuery的

'use strict';

function drawBlock(ctx, color, line_width, start, lines) {
    ctx.lineWidth = line_width;
    ctx.strokeStyle = color;

    ctx.beginPath();

    ctx.moveTo(start[0], start[1]);

    for (var i = 0; i < lines.length; i++) {
        ctx.lineTo(lines[i][0], lines[i][1]);
    }

    ctx.closePath();
    ctx.stroke();
}

function drawBg() {
    var absBg = document.getElementById('absBg');
    var ctx = absBg.getContext('2d');

    var demo_red = 'red';
    var grey = '#28282';

    var color = demo_red;

    drawBlock(ctx, color, 1, [185, 87], [[205, 75], [226, 98], [207, 110]]);
    drawBlock(ctx, color, 1, [235, 60], [[253, 50], [272, 71], [254, 81]]);
}

$(document).ready(function () {
    drawBg();

    // Scroll trigger
    $(window).scroll(function () {

    });
});

该演示使用您拥有的实际背景图像作为背景模型,您可以使用画布进行绘制。这样您就可以模仿原始图像的外观。

您可以尝试管理某种“差异数组”,其中存储哪些块在哪些位置不同。通过这种方式,您可以使用某些参数触发scroll上的函数,以便根据该更改绘图。

我希望你不要“需要”图像本身。使用画布绘图比加载大量图像要快得多:)

答案 3 :(得分:1)

这是一个有效的解决方案(2014.7.11)在firefox 30.0,chrome 35.0,opera 22.0,即11.0:

第1步:在.htaccess 添加以下行:

# cache for images
<FilesMatch "\.(png)$">
Header set Cache-Control "max-age=10000, public"
</FilesMatch>

第2步:添加图片预加载,例如

var pics = []; // CREATE PICS ARRAY

$(document).ready(function(){
    ...
    preload(
        '/public/images/stars.red.1.star.png',
        '/public/images/stars.red.2.star.png',
        '/public/images/stars.red.3.star.png',
        '/public/images/stars.red.4.star.png',
        '/public/images/stars.red.5.star.png',
        '/public/images/stars.empty.png'
    );
    ...
    $('.rating').on('mousemove', function(event){
        var x = event.pageX - this.offsetLeft;
        var id = getIdByCoord(x); //
        if ($(this).data('current-image') != id) {
            $(this).css('background-image', 'url(' + pics[id].src + ')');
            $(this).data('current-image', id);
        }
    })
    ...
})

...

// PRELOAD FUNCTION TO SET UP PICS ARRAY IN MEMORY USING IMAGE OBJECT
function preload() {
    for (i = 0; i < arguments.length; i++) {
        pics[i] = new Image();
        pics[i].src = arguments[i];
        // alert("preload " + arguments[i]);
    }
}

P.S。谢谢Shawn Altman