【问题标题】:How to prevent a background image flickering on change如何防止背景图像在更改时闪烁
【发布时间】:2014-04-11 18:16:19
【问题描述】:

我正在通过 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 中确实很糟糕。有可能阻止这种情况吗?我不认为它会发生,因为它是一个 dataurl,因此不需要下载。

解决方案:

// 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;

【问题讨论】:

  • 您的解决方案效果很好。考虑添加一个答案:)
  • 我知道这是一个老问题,但我在 Safari 上遇到了同样的问题,即使使用了 onload 技巧。这仍然适用于最新版本的 Safari 吗?铬很好。
  • 我喜欢这个解决方案!我有 257 张 1700 x 956 的图像在我的 node-webkit 应用程序中作为背景图像播放,非常漂亮。 Node-webkit 默认不会播放很多电影;可以通过大量的头发拉动和网络嵌合体插件来实现。非常感谢你给我指路。这是在经历了 4 个小时的挫折之后。你把我的生命还给了我。
  • @logidelic 你找到解决方案了吗?我在 FF 和 Safari 上也存在问题。适用于 Chrome、Edge、IE 11 等。
  • 像魅力一样工作!感谢那!节省了我的工作时间。

标签: javascript html css image


【解决方案1】:

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

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

它应该有助于闪烁..

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

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

另一种选择是使用图像而不是 DIV,并且只更改图像 url。

【讨论】:

  • 不幸的是似乎没有阻止它。我设法通过按照建议将其预加载到图像来完全停止它。谢谢你的回答。
  • 我只需要预加载来修复我的闪烁 - 不需要 CSS visibility 规则。
  • 在 iphone X 上闪烁,您在 div 上强制硬件加速的解决方案修复了它。谢谢!
【解决方案2】:

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

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

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

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

【讨论】:

  • 谢谢,我首先通过Image 加载它。我在这个例子中编辑了我原来的问题。
  • 卡在这上面好久了!也很容易解决。我希望我可以使用精灵图像,但我的图像太大了!再次感谢 ++
  • 我只需要预加载来修复我的闪烁 - 不需要 CSS visibility 规则。
  • @Air,在移动设备上运行 CSS3 动画时,您需要在某些元素上添加 backface-visibility 以防止闪烁。但这是“资源预加载器”的另一种情况。
【解决方案3】:

像这样预加载您的图像,无需包含&lt;img&gt;display: none

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

【讨论】:

    【解决方案4】:

    我为此苦苦挣扎了一会儿,尝试了预加载、将图像附加到文档等。

    最后,我重新保存了没有“渐进式”选项的 JPEG

    修复了交换 img src 时滚动闪烁的问题。

    【讨论】:

      【解决方案5】:

      嘿,伙计们,我知道这是一个较老的问题,但如果您在所有这些之后仍然闪烁,您可以简单地将最终版本放在背景 div 后面。该闪烁显示在您当前拥有的图像后面,因此如果它是最终图像,它将是平滑的。

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

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

          到目前为止,我想出的最佳解决方案是在子 canvas 内部绘制图像,填充整个父 div 的空间。

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

          【讨论】:

            【解决方案8】:

            我现在可以使用的 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 pic 替换长 URL,例如它不起作用,并且如果我第一次在分配中包含图像对象声明和位置,则闪烁停止。

            【讨论】:

              【解决方案9】:

              这并没有解决 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 滑入和滑出视图,而不会出现任何闪烁。

              关于加载事件

              您不能依赖加载事件触发。例如,当浏览器缓存了图像时,它通常不会触发。因此,为了使长篇文章更长,这是我在代码中为适应这一现实而进行的增强...

              我将 document.ready 事件(如上所示)修改为如下所示:

              $(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 可以查找预加载元素的存在,以便检查发生在一个地方。它可能相当花哨,所以我为这篇文章选择了最简单的例子。

              在许多情况下,我只需要这个精简版本,因为通常我只使用高分辨率照片作为窗口背景图像。我要么从显示低分辨率图像开始,并在加载高分辨率文件后立即将其关闭,要么在我确认存在高分辨率图像后触发一些动画。

              更通用的版本的一个很好的例子是,当我需要一开始就加载一系列图像并且不想在所有图像都准备好之前开始。在这些情况下,网页可能会以一些欢迎文本开始,直到所有图像都得到确认。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2020-08-17
                • 2017-08-24
                • 2018-02-09
                • 2013-04-17
                • 2019-05-23
                • 1970-01-01
                • 2014-03-19
                相关资源
                最近更新 更多