如何在<picture>元素内为<img>元素设置宽度和高度属性以防止布局变化?

13

在Chrome DevTools中运行Lighthouse,它显示需要改善CLS(累积布局移位)。

我知道现代浏览器现在根据图像的widthheight属性设置默认的宽高比。因此,最佳实践是要设置widthheight属性,以防止布局移位。

尽管如此,我没有设置widthheight属性,因为这是我唯一能让其按照我想要的方式工作的方法(请查看下面的代码)。

由于我的图片是WebP格式(带有png回退),我被迫使用<picture>元素(以便不支持WebP的浏览器获得图像的png版本)。请注意,我正在使用不同大小的相同图像版本。

因此,如果我没有使用WebP格式,我将仅使用<img>而不是<picture>。然后,由于纵横比,问题将会解决。

正如您在下面的代码片段中所看到的,在此特定示例中有两个版本的相同图像。在<img>中设置width="245"height="600"会导致我两个不同大小的相同图像版本都达到最大的245 x 600px尺寸(当然会按照较小的视口缩小)。对于更宽的视口(min-width:813px),根据我的媒体查询,我正在提供较大版本的相同图像,但在<img>中设置widthheight时,图像缩小为245 x 600px。

现在是我的问题/问题; 如果可能,如何在<picture>元素内设置<img>元素的widthheight属性以避免布局移位(并获得其他好处,例如更快的加载时间)?因此,如何让浏览器使用纵横比正确显示我的图像?

我真的很感激有人指导我。

谢谢/卡尔

<picture>
            <source 
              media="(max-width: 812px)" 
              srcset="image-245w.webp"
              type="image/webp"
            >
            <source 
              media="(min-width: 813px)" 
              srcset="image-332w.webp"
              type="image/webp"
            >
            <source 
              media="(max-width: 812px)" 
              srcset="image-245w.png"
              type="image/png"
            >
            <source 
              media="(min-width: 813px)" 
              srcset="image-332w.png"
              type="image/png"
            >
            <img class="img-fluid" src="image-245w.png" alt="image">     
</picture>

从技术上讲,您没有应用高度或宽度。在此片段中,您没有包含任何具有高度或宽度的CSS。在编辑之前,您有属性:width="600",但从技术上讲这是无效的。600是什么?宽度= 600个香蕉?西红柿?...您还需要命名一个单位,例如px,vw / vh,em,%... - tacoshy
2
你好,是的,我在文本中省略了 px。实际上,在属性“width”和“height”中不需要指定任何东西。正确的写法是 width="245" height="600",不需要 px、em 或其他单位。 - CarlB
我发现在HTML规范中,<source>元素定义了widthheight属性。https://html.spec.whatwg.org/multipage/embedded-content.html#the-source-element。当它被用在`<picture>`元素中时。但是我没有测试过这是否会在没有CLS的情况下工作。 - Leif Marcus
6个回答

1
允许在元素上使用width和height属性现在已经在规范中被定义,并且浏览器开始采用它。 GitHub问题

0
@media (max-width: 812px) {
    .img-fluid {
       width: 245px;
       height: auto;
    }
  }
  @media (min-width: 813px) {
    .img-fluid {
       width: 332px;
       height: auto;
    }
  }

3
您能否详细说明您建议的要点? - dakab

0

我进行了一些测试,并得出结论,使用图像元素上的widthheight(应该这样做)会取消sizes属性。如果设置widthheight,则无法使响应式图像正常工作。

我创建了一个小仓库,展示了不同的组合:https://www.gijsvandam.nl/responsive-picture-element/

解决方法是,如果您使用widthheight,则不要使用sizes,而是依靠CSS来设置正确的宽度和高度。

<picture>
            <source 
              srcset="image-245w.webp 245w, image-332w.webp 332w"
              type="image/webp"
            >
            <img
              srcset="image-245w.png 245w, image-332w.png 332w" 
              class="img-fluid" 
              src="image-245w.png" 
              alt="image" 
              width="245" 
              height="600">     
</picture>

     @media (max-width: 812px) {
        .img-fluid {
           width: 245px;
           height: auto;
        }
      }
      @media (min-width: 813px) {
        .img-fluid {
           width: 332px;
           height: auto;
        }
      }

了解使用srcSetsizes(或与上面的css组合使用)并不一定强制浏览器使用其中一张图片而非另一张图片很重要。根据设备像素比,浏览器可能选择加载较大的图像以显示在245px宽的图像插槽中。您只需要信任浏览器会选择最适合该作业的文件即可。 'sizes'和srcSet之间没有一对一的关系。这就是为什么您可以在srcSet中提供更多(或更少)的文件,而在sizes属性中却没有选项的原因。


但是如果您删除“sizes”,浏览器如何选择最合适的图像呢?难道“sizes”不是告诉浏览器“对于屏幕尺寸x,将显示宽度为y的图片”,然后浏览器可以选择最合适的大小进行下载吗? - Erik H
@ErikH 是的,但是如果您省略了sizes参数,浏览器仍然可以(并且会)使用CSS来确定图像的宽度,并根据此选择最合适的文件进行下载。但这确实有一个显著的缺点。浏览器必须在开始下载最合适的文件之前解析CSS。有了sizes属性,浏览器可以立即开始下载。 - gijswijs
谢谢你澄清了@gijswijs。那么,你建议保留sizes还是不保留? - Erik H
我认为这取决于你的情况。如果SEO排名很重要,我不会使用sizes,而是使用'height'和'width',这样你在Pagespeed Insights上得分更高,这是SEO排名的一个因素。如果SEO排名不重要,我会使用sizes - gijswijs

0

/* displays the image at 245x600px for small screens */

@media only screen
  and (max-width: /*enter a width in px */) {
    .img-fluid {
      height: 245px;
      width: 600px;
    }
}

/* displays the image at 332x812px for small screens */

@media only screen
  and (min-width: /*enter a width of max-width +1px*/) {
    .img-fluid {
      height: 332px;
      width: 812px;
    }
}
      
<img class="img-fluid" src="image-245w.png" alt="image"> 


欢迎来到SO!请不要发布仅包含代码的答案,而是添加一些文字说明您的方法如何运作以及它与其他给出答案的不同之处。您可以在我们的“如何撰写好答案”页面了解更多信息。 - ahuemmer

0

ex- img.d-blocks, img.d-block_w-100, img.d-block-w-100 { max-width: 20% }

}


-1
无论你尝试做什么,如果你尝试去完成它的方式太复杂了。你可以使用同一张图片并使用CSS调整大小。使用媒体查询根据屏幕宽度声明不同大小的图像,如下所示。

/* displays the image at 245x600px for small screens */

@media only screen
  and (max-width: /*enter a width in px */) {
    .img-fluid {
      height: 245px;
      width: 600px;
    }
}

/* displays the image at 332x812px for small screens */

@media only screen
  and (min-width: /*enter a width of max-width +1px*/) {
    .img-fluid {
      height: 332px;
      width: 812px;
    }
}
      
<img class="img-fluid" src="image-245w.png" alt="image"> 


1
感谢您的回答!这实际上就是我在代码中所做的。通过省略<img>中的宽度和高度属性,我依赖于我的媒体查询。它完美地工作,但是我会因为省略它们而收到CLS,我相信您的代码也是如此。现在,您需要添加这些属性以避免CLS,问题是如何在<picture>元素中实现? - CarlB
同时,我以响应式的方式提供不同尺寸的同一张图片,而不是为不同的视口调整一个图片的大小。这将会消耗带宽。 - CarlB
调整图像大小不会消耗带宽。但是,如果提供多个图像,则会消耗带宽,因为需要加载多个图像。使用CSS调整图像大小只需一次加载图像即可。例如,如果您将智能手机从纵向切换到横向,则会以您所做的方式重新加载图像。 - tacoshy
4
是的,仅提供一张图片确实会消耗带宽。想象一下你有一张要在电影院和智能手机上展示的巨大图片。这个图片非常大。在智能手机上展示这个图片(大量缩小它)并不是一个好主意,因为它与电影院使用的同样重的图片相同,因此将比为智能手机提供同一图片的较小/轻版本更加耗费带宽。提供多张图片并不等于所有图片都被使用/加载。只有符合设置条件(媒体查询)所需的那些图片将被显示。 - CarlB

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