响应式图片:使用srcset、sizes和媒体查询,避免加载高像素密度的大图。

5

我曾经使用图片元素来实现响应式图片在不同视口大小下的展示,效果还不错。但现在我被迫转向使用带有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 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"
/>

这在浏览器的首次测试中似乎很好用。但是后来我注意到,在移动设备上加载了太大的图像。

原因是一些移动设备的像素密度不同,就像响应式图片的完整指南所解释的那样。

您也可以使用Firefox的开发工具模拟这种情况: 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"
/>

不起作用...(它总是为所有视点加载最小的图像)
我尝试了一个没有媒体查询的解决方案,大小从使用img srcset处理响应式图片开始
不像我需要的那样工作...
所以重要的问题是,如何组合宽度和密度选择器。
在我的例子中,它应该加载:
740.jpg的宽度为0-740
1280.jpg的宽度为740-980
1600.jpg的宽度为980-1280
1920.jpg的宽度为更大
我不希望它为具有更高像素密度的设备加载更大的图像。
我知道在Stackoverflow上有很多类似的问题,我已经搜索了几周寻找一个有效的解决方案,但似乎没有像预期的那样工作,所以我希望有人能提供一个解决方案。
更新: 我发现有一个gitlab问题讨论了这个问题。

2

(请参见响应式图片会导致性能问题

但目前似乎还没有最终的解决方案。

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

2个回答

2

我找到了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,并获取1000px的图像
  • 因此,我尝试为所需大小(例如1000px)的双倍定义新的媒体查询,当由像素比设备时,它会获取我所需的500px

总之,这意味着:

如果您想要还原浏览器为具有大像素密度的移动设备获取更大图像的效果,则必须为每个像素密度计算新值。

对于两种解决方案,您也应通过CSS定义显示大小。

例如,此简单的PHP代码示例显示了:

<?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";
  }
?>

0

我还没有测试过你的第一个例子,但从技术上来说它应该是有效的。如果浏览器在下载图片之前也使用了 srcset "sizes" 来阻挡布局,那么在 CSS 中真实的图像宽度和高度被应用后,布局可能会出现闪烁变化。


第一个例子在短时间内确实有效,但当像素密度高于1的移动设备出现时,它会崩溃。后来我找到了一个可行的解决方案(请参见下面我的答案 https://dev59.com/YcLra4cB1Zd3GeqPJXDA#69637293)。 - Radon8472

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接