首先加载低分辨率背景图像,然后加载高分辨率背景图像

Load a low-res background image first, then a high-res one

我正在尝试在将网站输出到客户端时优化网站的大小。缓存时我下降到 1.9MB 和 29KB。问题是第一次加载包含的图像对于移动设备来说是非常不优化的;它具有 1080p 分辨率。

所以我正在寻找一种方法,允许我首先加载低分辨率版本 (min.bg.jpg),一旦网站加载完毕,使用高分辨率版本 - 甚至是具有分辨率的版本靠近正在使用的设备(NNNxNNN.bg.jpgbg.jpg)。

背景是使用 CSS 设置的,正如大家所期望的那样。它应用于正文,整个语句如下所示:

body {
    background: url("/cdn/theme/images/bg.jpg");
    color: white;
    height: 100%;
    width: 100%;
    background-repeat: no-repeat;
    background-position: 50% 50%;
    background-attachment: fixed;
}

现在,我想将其更改为使用 min.bg.jpg 而不是第一次加载,然后是这样的:

jQuery(function(){
    jQuery("body").[...]
});

我应该用哪种方式继续异步下载新背景,然后将其作为新 CSS 背景图片插入?

为了显示一些差异,这里是我用于测试的主要版本和迷你版本的示例:

Ingwie@Ingwies-Macbook-Pro.local ~/Work/BIRD3/cdn/theme/images $ file *.jpg
bg.jpg:     JPEG image data, EXIF standard
min.bg.jpg: JPEG image data, JFIF standard 1.01
Ingwie@Ingwies-Macbook-Pro.local ~/Work/BIRD3/cdn/theme/images $ du -h *.jpg
1,0M    bg.jpg
620K    min.bg.jpg

这是我使用的方法...

CSS:

#div_whatever {
   position: whatever;
   background-repeat: no-repeat;
   background-position: whatever whatever; 
   background-image: url(dir/image.jpg);
   /* image.jpg is a low-resolution at 30% quality. */
}

#img_highQuality {
    display: none;
}

HTML:

<img id="img_highQuality" src="dir/image.png">
<!-- img.png is a full-resolution image. -->

<div id="div_whatever"></div>

JQUERY:

$("#img_highQuality").off().on("load", function() {
    $("#div_whatever").css({
        "background-image" : "url(dir/image.png)"
    });
});
// Side note: I usually define CSS arrays because
// I inevitably want to go back and add another 
// property at some point.

发生了什么:

  1. 快速加载背景的低分辨率版本。
  2. 同时,高分辨率版本作为隐藏图像加载。
  3. 加载高分辨率图像时,jQuery 将 div 的低分辨率图像替换为高分辨率版本。

纯 JS 版本

此示例对于更改一对多元素非常有效。

CSS:

.hidden {
   display: none;
}

#div_whatever {
   position: whatever;
   background-repeat: no-repeat;
   background-position: whatever whatever; 
   background-image: url(dir/image.jpg);
   /* image.jpg is a low-resolution at 30% quality. */
}

HTML:

<div id="div_whatever"></div>
<img id="img_whatever" class="hidden" src="dir/image.png" onload="upgradeImage(this);">

JAVASCRIPT:

function upgradeImage(object) {
    var id = object.id;
    var target = "div_" + id.substring(4);

    document.getElementById(target).style.backgroundImage = "url(" + object.src + ")";
}

更新/增强(1/31/2017)

此增强功能受到 gdbj's excellent point that my solution results in the image path being specified in three locations. Although I didn't use gdbj 的 addClass() 技术的启发,修改了以下 jQuery 代码以提取图像路径(而不是硬连线到 jQuery代码)。更重要的是,此版本允许将多个低分辨率图像替换为高分辨率图像。

CSS

.img_highres {
  display: none;
}

#div_whatever1 {
  width: 100px;
  height: 100px;
  background-repeat: no-repeat;
  background-position: center center;
  background-image: url(PATH_TO_LOW_RES_PHOTO_1);
}

#div_whatever2 {
  width: 200px;
  height: 200px;
  background-repeat: no-repeat;
  background-position: center center;
  background-image: url(PATH_TO_LOW_RES_PHOTO_2);
}

HTML

<div id="div_whatever1"></div>
<img id="img_whatever1" class="img_highres" src="PATH_TO_HIGH_RES_PHOTO_1">

<div id="div_whatever2"></div>
<img id="img_whatever2" class="img_highres" src="PATH_TO_HIGH_RES_PHOTO_2">

JQUERY

  $(function() {
      $(".img_highres").off().on("load", function() {
         var id = $(this).attr("id");
         var highres = $(this).attr("src").toString();
         var target = "#div_" + id.substring(4);
         $(target).css("background-image", "url(" + highres + ")");
      });
   });

发生了什么:

  1. 根据 CSS 为每个 div 加载低分辨率图像 背景图像设置。 (请注意,CSS 还将 div 设置为预期的 尺寸。)
  2. 与此同时,正在处理更高分辨率的照片 作为隐藏图像加载(全部共享 class 名称 img_highres)。
  3. 每张img_highres张照片触发一个jQuery函数 完成加载。
  4. jQuery函数读取图片src路径,并 更改相应 div 的背景图像。在里面 上面的例子,可见的 divs 的命名约定是 "div_[name]" 和 "img_[same name]" 用于加载在 背景。

我通常会使用 Grunt 或 Tiny PNG 等在线工具优化图像以减小文件大小。

然后你可以选择延迟加载图像,我发现以下文章对延迟图像很有帮助 - https://www.feedthebot.com/pagespeed/defer-images.html

本文讨论了使用 base64 图像进行初始加载,然后延迟加载高质量图像。文中提到的图片标注如下...

<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="your-image-here">

文中提到的JavaScript如下...

window.addEventListener("load", () => {
  const images = document.querySelectorAll("img");
  for (let img of images)
    if (img.hasAttribute("data-src"))
      img.src = imgDefer[i].getAttribute("data-src");
});

希望对您有所帮助。

让我们试试基本的:

<img border="0" 
     style="background:url(http://i.stack.imgur.com/zWfJ5.jpg) no-repeat; 
            width:1920px;
            height:1200px"
     src="http://i.stack.imgur.com/XOYra.jpg" width="1920" height="1200" />

zWfJ5.jpg是low-resolution版本,XOYra.jpg是high-resolution版本。

如果有一种方法可以安排加载以便 background-image 先显示,这可能是我能想到的最简单的方法。

其中低分辨率 44k:

高分辨率为1.16M

结果:

jsFiddled here(加载比较需要更大的图片。)

有点晚了,但您可以使用这个极其简单的解决方案: 您可以将两张图片放在css背景中:

  background-image: url("high-res.jpg"),url("low-res.jpg");

浏览器会先显示 low-res 图片,然后在加载后在 low-res 上显示 high-res。

上面的所有答案大多都需要稍作调整,但这是我认为简短而简单的开始方式。

注:

  • 取消注释代码加载高分辨率图像以供使用,休眠功能仅用于模拟慢速网络。
  • 实际上,此方法不会同时加载 2 个资源(低和高),但这是可以接受的,因为低资源不会花费太多时间来加载。
  • 只需复制整个代码并运行进行快速检查。

<!DOCTYPE html>
<html>
  <head>
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>

    <style type="text/css">
      
    </style>
  </head>

  <body>
    <!-- Load low res image first -->
    <img style="width: 400px; height: auto;" alt="" src="https://s3-ap-southeast-1.amazonaws.com/wheredat/banner-low-quality/banner_20180725_123048.jpg" onload="upgrade(this)">
  </body>
  
  <script type="text/javascript">

 function upgrade(image){

                // After load low res image, remove onload listener.

  // Remove onload listener.
  $(image).prop("onload", null);

                // Load high resolution image.
                // $(image).attr('src', 'https://s3-ap-southeast-1.amazonaws.com/wheredat/banner/banner_20180725_123048.jpeg');

  // Simulate slow network, after 1.5s, the high res image loads.
  sleep(1500).then(() => {
      // Do something after the sleep!

   // Load a high resolution image.
   $(image).attr('src', 'https://s3-ap-southeast-1.amazonaws.com/wheredat/banner/banner_20180725_123048.jpeg');
  }); 
 }

 // Sleep time expects milliseconds
 function sleep (time) {
   return new Promise((resolve) => setTimeout(resolve, time));
 }

  </script>
  
</html>

在 Ubuntu / Chrome 71 上,Milche 的回答对我来说并不一致,高分辨率图像(通过 img src)经常在较低分辨率图像之前加载和解析( via css background) 甚至开始下载。

我的解决方案是从低分辨率图像开始作为 src 并使用 Image class 创建一个带有高分辨率图像的独立 <img> 实例.加载后,使用高分辨率图像源更新现有 <img> 源。

HTML:

<img id='my-image' src='low-res.png' alt='Title' width='1920px' height='1200px'>

JavaScript:

window.addEventListener('load', function() {
    loadHighResImage(document.getElementById('my-image'), 'high-res.png')
})

function loadHighResImage(elem, highResUrl) {
    let image = new Image()
    image.addEventListener('load', () => elem.src = highResUrl)
    image.src = highResUrl
}

Fiddle: https://jsfiddle.net/25aqmd67/

这种方法也适用于简单缩小的低分辨率图像。