无固有尺寸的 SVG 图片在各浏览器中的渲染尺寸问题

故事

公司同事在做图片预览功能时发现,很多 SVG 图片在 Firefox 下通过 img 标签加载成功后,naturalWidth/naturalHeight 是 0,和其他浏览器表现不同。

这个事情让我有点好奇,按照经验,我觉得 Firefox 一般是最跟随标准的,但是它又何其他浏览器的实现都不相同。所以查了一些资料做了一些测试。经过简单测试后发现,没有 固有尺寸[1] 的 SVG 在不同浏览器上使用 img 标签渲染时的尺寸是不同的。

我用几个浏览器跑了一遍 CodePen 上的例子[2]

这个例子一共有四张图:

  1. viewBox 属性的正方图片
  2. viewBox 属性的非正方图片
  3. 没有 viewBox 属性的非正方图片
  4. viewBoxwidth, height 属性的非正方图片

分别在 Firefox v74, Chrome v80, Safari v13 里跑了一下代码:

document.querySelectorAll("img").forEach((el) => {
  console.log(
    "width",
    el.width,
    "height",
    el.height,
    "naturalWidth",
    el.naturalWidth,
    "naturalHeight",
    el.naturalHeight
  );
});

结果如下:

  • Firefox v74:
    • img.naturalWidth/img.naturalHeight
      • 1, 2, 3 的这个属性都返回 0
      • 4 返回 SVG 图片 width, height 属性的值
    • img.width/img.height
      • 1, 2 的 img.width 都是 100% 的计算值,img.height 按比例缩放
      • 3 返回 300x150
      • 4 返回 SVG 图片 width, height 属性的值
  • Chrome v80
    • img.naturalWidth/img.naturalHeight
      • 1, 2 的 naturalHeight 都返回 150naturalWidth 按比例缩放
      • 3 返回 300x150
      • 4 返回 SVG 图片 width, height 属性的值
    • img.width/img.height 和 Firefox 表现一致
  • Safari v13
    • img.naturalWidth/img.naturalHeight
      • 1, 2 的 naturalWidth 都返回 100% 的计算值,naturalHeight 按比例缩放
      • 3 返回 300x150
      • 4 返回 SVG 图片 width, height 属性的值
    • img.width/img.height 和 Firefox 表现一致

然后我查了一下 2020-04-09 时的 HTML 的标准对 naturalWidth 的描述

The IDL attributes naturalWidth and naturalHeight must return the density-corrected intrinsic width and height of the image, in CSS pixels, if the image has intrinsic dimensions and is available, or else 0.

看起来好像是 Firefox 的实现比较贴近当前的 HTML 标准。

那么如果我想体面地渲染一张随机的 SVG 图片,我该怎么办呢?

目前我没有想到什么特别好的方案,可能会需要自己根据需求来确定方案

  • 如果可以获取到 SVG 文件的代码,而且可以执行 JavaScript ,那么我们可以通过判断 <svg> 标签有没有 width, height 来确认图片是否有固有尺寸,有的话就直接使用 naturalWidth/naturalHeight ,没有的话就使用一 img.width/img.height 计算出宽高比,然后使用我们预置的宽度/高度来渲染图片,另外一边等比缩放
  • 如果没办法获取 SVG 文件的代码,或者没办法执行 JavaScript ,那么我们就只能给图片的外部套一个限制了宽高的容器了。如果图片有固有尺寸,那么图片会按照固有尺寸进行渲染(如果超出了我们限制的宽高它会等比缩放);如果没有固有尺寸,它就会自动缩放以适应我们限制的宽高

其他资料


  1. 固有尺寸(Intrinsic Dimensions)在 CSS 里指的是 object 内置的 偏好(preferred)/原生(natural) 的尺寸(the intrinsic height, intrinsic width, and intrinsic aspect ratio),CSS 标准里没有定义如何获取这部分信息。而在 SVG 图片这个上下文里,我们可以认为 SVG 图片的 width/height 属性就是它的固有尺寸。 https://drafts.csswg.org/css-images-3/#intrinsic-dimensions↩︎

  2. 来自 GitHub whatwg/html 上的 issue Make img.naturalWidth/Height handle dimensionless images better #3510↩︎