分层外观:使用多个背景实现更好的响应式图像

Avatar of Parker Bennett
Parker Bennett 发布

DigitalOcean 为您的旅程各个阶段提供云产品。立即开始使用 $200 的免费积分!

以下是由 Parker Bennett 发布的客座文章。Parker 之前曾在 CSS-Tricks 上发表过文章,在 Crop Top 文章中,他讨论了灵活图像的定位问题。这篇文章是对该文章的良好补充,在无休止的响应式图像传奇中,展示了另一种选择。它也与 昨天的文章 形成有趣的对比,您可以看到解决这个问题的不同方法。

我们希望网页加载速度快,我们希望有视网膜图像。我们可以兼得吗?

模拟“lowsrc” - 在移动优先页面加载后进行高分辨率颜色交换。

我们不想向不需要的人提供超大尺寸的图像。有几种方法可以避免这种情况,包括 Scott Jehl 的 picturefill、服务器端解决方案和 延迟加载技术,但最简单的方法可能是使用 background-image 和 CSS 媒体查询的魔力。这样,您幸运的视网膜用户就能获得高分辨率 @2x 版本,而我们其他人……好吧,至少我不必等待巨型文件下载。

(为了便于下面的说明,我将我的“移动优先”默认图像设置为黑白,中等尺寸版本设置为棕褐色,如果您将窗口调整到足够宽或使用高 DPI 屏幕,还会显示一个更大的彩色版本。)

小型黑白默认图像,当窗口变宽时,将切换为彩色图像。在图像缓存之前,加载时会出现短暂的闪屏。
/* base background-image class */
.bg-image {
  width: 100%;
  /* default background-position */
  background-position: center center;
  /* lt ie 8 */
  -ms-background-position-x: center;
  -ms-background-position-y: center;
  /* scale proportionately */
  background-size: cover;
  /* IE8 workaround - http://louisremi.github.io/background-size-polyfill/ */
  -ms-behavior: url(/backgroundsize.min.htc); }

/* mobile-first default (b&w) */
.bg-image-sedona {
  background-image: url(img/photo-sedona_512x320.jpg);
  background-position: center 21%; }

/* example media queries (IE8 needs this:
   http://code.google.com/p/css3-mediaqueries-js) */
@media
  /* "mama-bear" - plus any-retina */
  only screen and min-width : 513px,
  only screen and (-webkit-min-device-pixel-ratio: 1.5),
  only screen and (        min-device-pixel-ratio: 1.5) {

    /* mid-size (sepia) */
    .bg-image-sedona {
      background-image: url(img/photo-sedona_1024x640.jpg); }
  }

@media
  /* "papa-bear" - plus larger retina */
  only screen and (min-width : 1025px),
  only screen and (min-device-width : 768px) and (-webkit-min-device-pixel-ratio: 1.5),
  only screen and (min-device-width : 768px) and (        min-device-pixel-ratio: 1.5) {

    /* high-res (color) */
    .bg-image-sedona {
      background-image: url(img/[email protected]); }
  }

显示背景图像的 div 需要一个高度,可以手动设置,也可以像我在这里做的那样,通过包装一个设置为响应式缩放的透明“代理” img 来设置 (更多内容请见此处)。

现在,您可能已经注意到,页面第一次呈现大型图像时,加载过程中可能会出现明显的延迟。即使是较小的图像,在缓存之前,加载或替换时也可能会出现令人讨厌的闪屏。但我们可以解决这个问题……

CSS3 多重背景:它们如何叠放

在 CodePen 上编辑

较新的浏览器允许我们通过声明以逗号分隔的多个值来堆叠背景图像。通过这种方式,我们可以显示原始缓存的图像,同时替换图像平滑地加载到其上(请注意下面的代码中的 堆叠顺序)。

顶部为单一背景,底部为多个背景。

要查看它的实际效果,请缩小浏览器窗口并清空缓存(在 Chrome 菜单中选择“清除浏览数据”或在 Safari 的“开发”菜单中选择“清空缓存”)。现在重新加载页面。向下滚动到此处并将窗口扩展到彩色图像加载到顶部为止。(或者尝试此 弹出窗口。)

不幸的是,旧版浏览器(例如 IE8*)会看到多个背景声明并束手无策 - 不会显示任何内容(糟糕!)。因此,我们需要使用 modernizr.js 进行功能检测,并创建回退(如果我们希望这些浏览器显示的内容大于移动优先默认图像)。

/* .bg-image and .bg-image-sedona same as above.
   .multiplebgs class added by modernizer.js. */

@media
  /* "mama-bear" - plus any-retina */
  only screen and min-width : 513px,
  only screen and (-webkit-min-device-pixel-ratio: 1.5),
  only screen and (        min-device-pixel-ratio: 1.5) {

    /* no-multiplebgs - mid-size fallback (sepia) */
    .no-multiplebgs .bg-image-sedona,
    /* upscale to mid-size if no javascript */
    .no-js .bg-image-sedona {
      background-image: url(img/photo-sedona_1024x640.jpg); }

    .multiplebgs .bg-image-sedona {
      background-image:
        /* mid-size on top (sepia) */
        url(img/photo-sedona_1024x640.jpg),
        /* mobile-first default on bottom (b&w) */
        url(img/photo-sedona_512x320.jpg);
      }
  }

@media
  /* "papa-bear" - all three images */
  only screen and (min-width : 1025px) {

    /* no-multiplebgs fallback is above */

    .multiplebgs .bg-image-sedona {
      background-image:
        /* high-res on top (color) */
        url(img/[email protected]),
        /* mid-size in middle (sepia) */
        url(img/photo-sedona_1024x640.jpg),
        /* mobile-first default on bottom (b&w) */
        url(img/photo-sedona_512x320.jpg);
      }
  }

@media
  /* larger retina device - triggered immediately,
     so mid-size image not needed */

  only screen and (min-device-width : 768px) and
    (-webkit-min-device-pixel-ratio: 1.5),
  only screen and (min-device-width : 768px) and
    (        min-device-pixel-ratio: 1.5) {

    /* no-multiplebgs fallback is above */

    .multiplebgs .bg-image-sedona {
      background-image:
        /* high-res on top (color) */
        url(img/[email protected]),
        /* mobile-first default on bottom (b&w) */
        url(img/photo-sedona_512x640.jpg);
    }
  }

标准 JPEG 与渐进式 JPEG

对于 JPEG,图像在多重背景中渲染到另一个图像上的方式取决于它的保存方式。标准 JPEG 在下载时按顺序“绘制”图像。渐进式 JPEG 在完全下载后“出现”。(标准方式对我来说似乎更平滑。)请注意,像 ImageOptim 这样的图像压缩器默认设置为渐进式保存(Jpegrescan 已选中),因为它可以节省少量空间。

当然,我们不希望用户不必要地下载图像,也不想让维护变得过于复杂,因此,务必使断点保持克制,并从逻辑上进行思考。但是,现在我们可以使图像交换变得不那么显眼,这为我们打开了一些可能性……

模拟“lowsrc”

在 CodePen 上编辑

在蒸汽为互联网提供动力的时代,拨号接入速度非常慢,因此他们创建了一个特殊的属性,以便用户在下载动画 gif 的 1 分半钟时间内看到某些内容:它被称为“lowsrc”,看起来像这样:IMG SRC="big.gif" LOWSRC="small.gif"

浏览器在 20 世纪 50 年代后期停止支持此功能。

但是现在,类似的功能可能很有用,这样用户就可以在下载视网膜就绪的高分辨率图像的 2 秒半时间内看到某些内容。(而且别忘了,4K 即将到来。)

现代浏览器非常智能,可以在获取图像后立即填充图像,因此,通过指定较小、更压缩的“lowsrc”图像作为默认图像,然后在我们的 CSS 媒体查询中将它们叠放在 @2x 视网膜图像下方,事情可能会感觉更敏捷。我们可以使用 jQuery 更进一步……

其想法是在使用我们的默认“lowsrc”图像完全呈现页面之前,暂缓图像交换。然后,我们使用 jQuery 向我们的主要“bg-image”类添加“hd”类,这将触发我们的媒体查询来交换图像。我们也可以暂缓并“延迟加载”高分辨率图像,以便在滚动到它们时加载,使用类似于 jQuery Waypoints 插件 的内容。

/* .bg-image and .bg-image-sedona same as above
   .hd class added by jQuery after page loads
   (or perhaps "lazy loaded" as user scrolls) */

@media
  /* "mama-bear" - plus any-retina */
  only screen and (min-width : 513px),
  only screen and (-webkit-min-device-pixel-ratio: 1.5),
  only screen and (        min-device-pixel-ratio: 1.5) {

    /* no-multiplebgs - mid-size fallback */
    .no-multiplebgs .bg-image-sedona.hd,
    .no-js .bg-image-sedona {
      /* mid-size (sepia) */
      background-image: url(img/photo-sedona_1024x640.jpg); }

    .multiplebgs .bg-image-sedona.hd {
      background-image:
        /* mid-size on top (sepia) */
        url(img/photo-sedona_1024x640.jpg),
        /* mobile-first "lowsrc" on bottom (b&w) */
        url(img/photo-sedona_512x320.jpg); }
  }

@media
  /* "papa-bear" - size only */
  only screen and (min-width : 1025px) {

    /* no-multiplebgs fallback is above */

    .multiplebgs .bg-image-sedona.hd {
      background-image:
        /* high-res on top (color) */
        url(img/[email protected]),
        /* mid-size in middle (sepia) */
        url(img/photo-sedona_1024x640.jpg),
        /* mobile-first "lowsrc" on bottom (b&w) */
        url(img/photo-sedona_512x320.jpg); }
  }

@media
  /* larger retina device, triggered immediately,
     so mid-size image is not needed */
  only screen and (min-device-width : 768px) and
    (-webkit-min-device-pixel-ratio: 1.5),
  only screen and (min-device-width : 768px) and
    (        min-device-pixel-ratio: 1.5) {

    /* no-multiplebgs fallback is above */

    .multiplebgs .bg-image-sedona.hd {
      background-image:
        /* high-res on top (color) */
        url(img/[email protected]),
        /* mobile-first "lowsrc" on bottom (b&w) */
        url(img/photo-sedona_512x320.jpg); }
  }
/* waits until everything is loaded, not just DOM is ready */
$(window).load(function() {

  $('.bg-image').addClass('hd');

});

查看此“模拟 lowsrc”演示的实际效果

查看带有“延迟加载”的示例

/* "lazy loads" when .bg-image appears in viewport -
   http://imakewebthings.com/jquery-waypoints/ */

$('.bg-image').waypoint(function(direction) {
  if (direction === 'down') {
    $(this).addClass('hd');
  }
}, { offset: 'bottom-in-view', triggerOnce: true });

/* other offsets: '100%' (image top at viewport bottom),
   '125%' (just beyond the viewport, about to scroll in) */

总结

理想情况下,我希望看到这种方法以更自动化的方式工作,例如 picturefill.js,但从移动优先 img 而不是 data-src 属性进行扩展。你怎么看?您可以查看更多内容的源代码,在 CodePen 上查看所有演示,或者 在此处下载示例文件。如果您有任何问题、评论或更正,请给我留言:parker@parkerbennett.com.


* IE8 不支持多重背景,但如果您能为图像声明宽度和高度,则可以使用 Nicolas Gallagher 的 这种伪元素方法 来实现类似的功能。