具有 srcset、大小、媒体查询的响应图像 - 防止为更高的像素密度加载巨大的图像

responsive images with srcset, sizes, media-queries - Prevent loading huge images for higher pixel density

我长时间使用 picture element 来响应每个视口不同尺寸的图像。 它工作正常,但现在我被迫切换到使用 srcsetsizes 的响应式 <img> 并且我尝试将我的图片元素重写为 IMG 样式。

经过长时间的搜索,我在以下位置找到了很好的文档:

https://www.dofactory.com/html/img/sizes 更多详情请访问: https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images

带图片的代码是这样的:

<picture>
    <source media="(max-width: 740px)" src="740.jpg" type="image/jpeg">
    <source media="(max-width: 980px)" src="1280.jpg" type="image/jpeg">
    <source media="(max-width: 1280px)" src="1600.jpg" type="image/jpeg">
    <source media="(max-width: 1480px)" src="1920.jpg" type="image/jpeg">
    <img src="740.jpg" title="..." alt="..." />
</picture>  

我将其重写为响应式 img,如下所示:

<img src="740.jpg" title="..." alt="..." 
    srcset="
       740.jpg 740w,
       1280.jpg 1280w,
       1600.jpg 1600w,
       1920.jpg 1920w" 
    sizes="
       (max-width: 740px) 740px,
       (max-width: 980px) 1280px,
       (max-width: 1280px) 1600px,
       (max-width: 1480px) 1920px"
/>

这在浏览器中的第一次测试中似乎非常有效。 但后来我注意到在移动设备上加载的图片太大了。

原因是某些移动设备的像素密度不同,如在 a-complete-guide-for-responsive-images

你也可以用firefox的dev-tools来模拟这个:

我试图通过将代码更改为

来解决此问题
<img src="1920.jpg" title="..." alt="..." 
    srcset="
       740.jpg 740w 1x,
       1280.jpg 1280w 1x,
       1600.jpg 1600w 1x,
       1920.jpg 1920w 1x" 
    sizes="
       (max-width: 740px) 740px,
       (max-width: 980px) 1280px,
       (max-width: 1280px) 1600px,
       (max-width: 1480px) 1920px"
/>

不起作用...(它总是为所有视点加载最小的图像)

我尝试了一个没有媒体查询的解决方案,大小从 Handling responsive images with img srcset

没有像我需要的那样工作...

所以最大的问题是,如何组合宽度和密度的选择器。

在我的示例中,它应该加载:

而且我不希望它为具有更大像素密度的设备加载更大的图像。

我知道 Whosebug 中有很多类似的问题,我正在搜索数周的工作解决方案,但似乎没有任何效果像预期的那样,所以我希望有人可以提供解决方案

更新: 我发现,有一个讨论这个问题的 gitlab issue。

(参见 Responsive images causes performance issues

不过目前看来,这个问题似乎还没有最终的解决方案。

如果有人能提供新的想法,我们将非常高兴。

我找到了 2 个可能的解决方案:

两者都使用 min-resolution 媒体查询来定义每个像素密度的单独大小。 我用一个比问题中更简单的例子来解释它:

想法 1

<img src="500.jpg" title="..." alt="..." 
    srcset="
       500.jpg 500w,
       1000.jpg 1000w"
    sizes="
       (min-resolution: 3dppx) 33vw,
       (min-resolution: 2dppx) 50vw,
       (min-resolution: 1dppx) 100vw"
/>

我使用了 100vh 示例,并“恢复”浏览器拍摄的图像是 current_with * pixel-density

此解决方案适用于全屏图像,但您可以使用自定义视口。

想法 2

<img src="500.jpg" title="..." alt="..." 
    srcset="
       500.jpg 500w,
       1000.jpg 1000w"
    sizes="
       (min-resolution: 3dppx) and (max-width: 600px) 1500px,
       (min-resolution: 3dppx) and (max-width: 1200px) 2000px,

       (min-resolution: 2dppx) and (max-width: 600px) 1000px,
       (min-resolution: 2dppx) and (max-width: 1200px) 2000px,

       (min-resolution: 1dppx) and (max-width: 600px) 500px,
       (min-resolution: 1dppx) and (max-width: 1200px) 1000px"
/>

我基于屏幕宽度创建了类似的媒体查询,但添加了“还原”浏览器拍摄图像的大小 current_with * pixel-density

此解决方案适用于所有图像,即使它们不是全尺寸。 这里可以使用自定义视口,但相对代码较多。

两者背后的基本思想:

  • 例如对于像素密度 2x 和 500px 屏幕宽度,浏览器选择双倍大小的 srcset,这是在 sizes media-query 中定义的,并采用 1000px - image
  • 所以我尝试为我想要的尺寸的两倍(例如 1000px)定义新的媒体查询,这需要浏览器获得我想要的 500px,当它由像素比
  • 设置时

在夏季,这意味着:

如果您想恢复浏览器为具有大像素密度的移动设备拍摄更大图像的效果,您必须为每个像素密度的尺寸计算新值。

对于这两种解决方案,您也应该通过 css 定义显示尺寸。

例如这个简单的例子 php-code 表明:

<?php
  $viewport = [
    // Viewport => Image-Size
    600  => 500,
    1200 => 1000
  ];

  // walk over all pixel-densities
  for($i=3; $i>0; $i--) {
    foreach($viewport as $vp => $w) 
      echo "(min-resolution: {$i}dppx) and (max-width: {$vp}px) "
            .floor($w/$i) . "px,\n";
  }
?>

我还没有测试过你的第一个例子,但它似乎在技术上应该可行。如果浏览器在下载图片之前也使用 srcset "sizes" 来屏蔽布局,那么在应用 CSS 中的真实图像宽度和高度后,布局可能会发生快速变化。