如何防止背景图像在变化时闪烁



我正在通过这样的JavaScript将重复的背景图像从画布上应用于DIV:

var img_canvas = document.createElement('canvas');
img_canvas.width = 16;
img_canvas.height = 16;
img_canvas.getContext('2d').drawImage(canvas, 0, 0, 16, 16);
var img = img_canvas.toDataURL("image/png");
document.querySelector('#div').style.backgroundImage = 'url(' + img + ')';

我必须经常更新它。问题在于它会随着变化而闪烁,它似乎没有发生在Chrome中,但在Firefox和Safari中确实很糟糕。有可能停止吗?我认为这不会发生,因为它是一个数据图,因此不需要下载。

解决方案:

// create a new Image object
var img_tag = new Image();
// when preload is complete, apply the image to the div
img_tag.onload = function() {
    document.querySelector('#div').style.backgroundImage = 'url(' + img + ')';
}
// setting 'src' actually starts the preload
img_tag.src = img;

尝试通过在DOM中加入DOM中的图像,例如以下HTML代码中将图像资源预加载到设备存储中。可能会出现错误,因为需要加载图像资源,这需要一些时间(闪烁)。

<img src="imageToPreload.png" style="display:none;" alt="" />

您可能更喜欢使用Sprites-images。通过使用Sprites,您的应用程序将需要更少的HTTP-要求将所有ressources加载到您的页面中。如果您使用的是css animations,还要添加以下CSS样式。它将防止在移动设备上闪烁背景:

-webkit-backface-visibility: hidden;
-moz-backface-visibility:    hidden;
-ms-backface-visibility:     hidden;

按照这样的图像预加载,无需将 <img>display: none

一起包含
<link rel="preload" href="/images/bg-min.png" as="image">

尝试将此CSS添加到您的背景元素:

-webkit-backface-visibility: hidden;
-moz-backface-visibility:    hidden;
-ms-backface-visibility:     hidden;

它应该有助于闪烁..

您还可以通过将其添加到您的背景元素中来"强制"硬件加速:

-webkit-transform: translate3d(0, 0, 0);

另一个选项是使用图像而不是DIV并仅更改图像URL。

我对此进行了努力,尝试预加载,附加文档的图像等

最后,i 在没有"渐进式" 选项的情况下重新保存了JPEG。

交换IMG SRC时修复了滚动闪烁。

在我的情况下,将height: 1080px;(背景高度)更改为height: fit-content;

我认为,在任何情况下,对所有图像进行预加载至关重要。我发现的是,浏览器在动态更改背景图像时的行为方式彼此不同。例如,在Firefox中,当更改频繁时,它会闪烁,但是在Chrome和Safari中没有。

到目前为止,我提出的最好的解决方案是绘制填充整个父级div空间的孩子canvas中的图像。

在所有情况下,您所使用的图像都必须优化,因为它会影响渲染性能。

我现在有效的JavaScript代码这个

const pic = new Image();
const pic2 = new Image();
pic.src="../images/settings_referrals_anim.gif";
pic2.src="../images/settings_referrals_still.png";

我实际上没有在查询中引用该代码,例如,我使用

document.querySelector(".button_Settings_referrals").addEventListener("mouseover", function() {
  myDiv.style.backgroundImage = "url('../images/settings_referrals_anim.gif')";

,但似乎有效。如果我用const图片替换长URL,例如它不起作用,如果我在分配中首次包括图像对象声明和位置,则闪烁停止。

这并不能解决OP指出的所有细节,但对他人可能很有用。在Chrome 97,Firefox 96,Android 11,iOS 15中测试。

我有一个包括这些CSS参数的div ...

#div_image {
    background-image: url( [Path to low-res image] );
    background-size: cover;
}

我有一个看起来像这样的相应类...

.div_image_highres {
    background-image: none !important;
}

相应类的伪元素定义如下:

.div_image_highres::before {
    position: absolute;
    left: 0;
    top: 0;
    
    width: 100%;
    height: 100%;
    
    content: " ";
    
    background-image: url( [Path to highres image] );
    background-repeat: no-repeat;
    background-position: 50% 0;
    background-size: cover;
    
    opacity: 1;
    display: block;
}

我有一个IMG元素,它也指向高分辨率图像...

<img id="img_highres_preload" src=" [Path to high-res image ] ">

IMG元素具有相应的样式,该样式允许显示图像(确保图像文件加载)但看不到...

#img_highres_preload {
    width: 1px;
    height: 1px;
}

两个注释:(1)我意识到很多人使用其他预加载方法(例如,以编程方式),但是我对此方法有个人喜好。(2)参见有关加载事件可靠性的附录。

最后但并非最不重要的一点是,我有一些JavaScript(jQuery),添加了"高分辨率"。班级为"div_image"一旦加载高分辨率的文件...

$(document).ready(function() {
    $("#img_highres_preload").off().on("load", function() {
        $("#div_image").addClass("div_image_highres");
    });
});

这很容易成为香草JS,但是由于我在整个代码中都使用jQuery,所以我喜欢保持一致性。


这是有关发生的事情的摘要...

  1. 大概是首先加载低分辨率图像,并成为DIV的背景图像。即使没有发生这种情况,一切都会按预期工作(即,将显示高分辨率图像)。
  2. 当高分辨率图像加载到IMG元素中时(即JavaScript确认加载高分辨率文件),"div_image_highres"类应用于" Div_image"。
  3. 结果,DIV不闪烁而切换到高分辨率图像。根据我的经验,如果有的话,它向左移动了一点。但这常常不会发生,如果这样做,那不是不远的。
  4. 这是我在需要时使用这种方法的主要原因:在我的应用程序中,有多个面板可以导航,这导致一个面板滑出视图,而新的面板则可以看到。如果我不使用伪元素(如上所述)显示高分辨率图像,则在隐藏并重新显示其DIV时闪烁图像。使用上述技术,我可以在不闪烁的情况下将DIV滑入和看不到视图。

关于加载事件

您不能依赖加载事件射击。例如,当浏览器缓存图像时,通常不会发射。因此,要使很长的帖子更长,这是我在代码中拥有的增强,以适应这一现实...

我修改了文档。dready事件(如上所示)以使其看起来像:

$(document).ready(function() {
    positionOnPage(true);
    
    $("#img_highres_preload").off().on("load", function() {
        checkImage();
    });
});
checkImage = function() {
    var image = $("#img_highres_preload")[0];
    
    if (!image.complete || (typeof image.naturalWidth != "undefined" && image.naturalWidth == 0)) {
        console.log("Waiting for high-res image.");
    }
    else if (!$("#div_home").hasClass("div_home_highres")) {
        $("#div_home").addClass("div_home_highres");
        $("#img_highres_preload").remove();
    }
}

CheckImage函数检查图像元素,以查看是否已加载了图像。在此代码示例中,这有点多余 - 也就是说,IMG元素已确认了负载,因此通常无需检查(除非有某些理由相信文件被误载)。

我可能会如图所示这样做,因为我也从代码中的其他位置调用Checkimage,因此,如果我有更多的程序化响应(与所示的简单版本不同),我希望所有这些代码都在同一地点并写成就一次。由计时器触发时或即将显示显示预期图像的部分时,可以调用Checkimage函数。也许这样的东西...

if (sectionName == "[whatever]" && $("#img_highres_preload").length === 1) {
    checkImage();
}

在此示例中,我要寻找预紧img元素的存在,因为我知道我以前的函数在实现其目的后会删除该元素。

这篇文章有一个剥离版本来说明该概念。如上所述,它仅容纳一个已知的IMG元素,因此可以将代码扩展到使用某些参数(例如,图像或元素本身的名称)和CheckImage来调用CheckImage,并且CheckImage可以查找预订元素的存在,因此,检查发生在一个地方。这可能是相当花哨的,所以我使用了这篇文章的最简单示例。

在许多情况下,我只需要这个剥离版本,因为通常我只为窗口背景图像使用高分辨率照片。我要么从显示低分辨率图像的显示开始,然后在加载高分辨率文件后立即将其切换出来,要么在确认高分辨率图像存在后会触发一些动画。

对于更广泛的版本来说,一个很好的情况是,当我一开始需要加载一系列图像,并且不想在所有这些图像都准备好之前开始。在这些情况下,网页可能以一些可喜的文本开头,直到所有图像都被确认为止。

嘿,我知道这是一个较旧的问题,但是如果您仍然闪烁,那么您可以简单地将最终版本放在您的背景div后面。那个闪烁正在看到您当前拥有的图像后面,因此,如果它的最终图像将很顺利。

最新更新