如何使用<svg>的viewBox属性?

91
我正在学习SVG,它的官方文档中有这样一行代码。我不理解,如果它已经有了widthheight属性,那在viewBox="0 0 1500 1000"中再次指定它的意义是什么?官方文档说:“一个像素被定义为等于一个用户单位。因此,在官方文档中,“5px”的长度与“5”的长度相同,因此这个视图盒是一个1500像素宽、1000像素高的视图,超出了300像素和200像素。那么为什么要首先定义宽度和高度的值呢?
 <svg width="300px" height="200px" version="1.1"
         viewBox="0 0 1500 1000" preserveAspectRatio="none"
         xmlns="http://www.w3.org/2000/svg">
7个回答

100
宽度和高度定义了 <svg> 的大小。而 viewBox 控制着 <svg> 元素内的内容如何展示,因此 viewBox="0 0 1500 1000" 会将 <svg> 元素内的内容缩小 5 倍(1500 / 300 = 5, 1000 / 200 = 5)。与没有 viewBox 的情况相比,缩小后的内容尺寸为原来的 1/5,但是 <svg> 元素的大小并未改变。
想象一下你有一个弹性表面,把它切成四等分。如果你扔掉三份,则剩下的表面积是原表面积的 1/4。现在,如果你拉伸这个表面使它恢复到原始大小,则表面上的所有东西都会变成两倍大。这就是 viewBox 和宽度/高度之间的关系。

1
缩小比例?如果没有viewBox,图像将是300像素宽,现在必须被拉伸到1500像素宽。我会称之为放大,以5倍于指定大小显示内容。 - Elise van Looij
这里是关于编程的相关内容:*<svg>有多大* - 等等,如果不是绘制所有元素所需的区域,那么“<svg/>大小”是什么?我的意思是,元素不已经定义了吗?(如果有偏离主题的话请原谅,但是<svg/>宽度和高度以及其元素之间的关系比viewBox本身更让我困惑。) - Alois Mahdal
@AloisMahdal,请提出一个带有完整信息的问题。通过评论来回交流不是最好的方法。 - Robert Longson

43

默认情况下

<svg width="300" height="200">

SVG网格的“标尺”以像素为单位(该SVG中的所有形状都以像素为单位测量)。

但如果您想使用自己的单位,则可以使用viewBox属性:

<svg width="300" height="200" viewBox="0 0 1500 1000">

这意味着:

水平轴:1500(你的宽度单位)= 300px => 1(你的宽度单位)= 300/1500px = 1/5px

垂直轴:1000(你的高度单位)= 200px => 1(你的高度单位)= 200/1000px = 1/5px

  • 现在svg中的所有形状都会被缩放:

他们的宽度相对于原始大小缩小到1/5px(1/5 < 1 => 缩小比例)。

他们的高度也相对于原始大小缩小到1/5px(1/5 < 1 => 缩小比例)。


3
很好的解释。我已经阅读了很多关于SVG的东西,但没有一个清晰明了的。你的回答帮助我理解了缩放,谢谢! - FraK
1
我完全同意。这应该被标记为最佳答案。 - Uchenna Ajah

35
如果您未指定视口(viewbox),则元素中的所有无单位数值都被认为是像素。(而SVG假设90dpi或每英寸像素数用于从像厘米这样的单位转换为像素。)
视口可以让您将元素中的无单位数值解释为"用户单位"并指定如何将这些单位映射到大小上。为简单起见,考虑仅在x坐标轴上即标尺。您的视口表示您的标尺将有1500个单位来匹配svg的200像素宽度。
一条从0到1500(无单位,即用户单位)的直线元素会在绘制时拉伸200像素,也就是横跨svg图形的宽度。
(由于SVG可以无损缩放,因此当用户放大或缩小时,像素在现实世界中并没有太多意义。)
这是一种坐标变换方式。
我建议您从像《SVG Essentials》这样的书中学习,它只需10美元左右的使用费,我在这里引用了其中的部分内容。

2
我认为它是96dpi而不是90dpi。至少在Inkscape中是这样,以防他们实现了一些非标准的东西。 - Saren Tasciyan

9

主要内容:

  • viewBox属性与SVG中的视口(viewport)密切相关。

缩写:

  • viewBox - VB
  • viewport - VP
  • viewport coordinate system - VCS
  • local coordinate system - LCS

语法:

<svg x = "VP_min_X" y = "VP_min_Y" width = "VP_width" height = "VP_height"
viewBox = "VB_min_X VB_min_Y VB_width VB_height">

默认值:

  • 单位 = 像素(px)
  • 视口宽度 = 300
  • 视口高度 = 150
  • 视图框(viewBox) = 视口

带有默认值的代码:

<svg>

相同结果的代码:

<svg x = "0" y = "0" width = "300" height = "150" viewBox = "0 0 300 150">

视口设置:
视口坐标系(VCS)的原点:

  • VP_min_X
  • VP_min_Y

在最外层的视口中,这些值并不重要,无论如何都将等于0,通常被省略:

<svg width = "100" height = "150">

具有相同结果的代码:(针对最外部视口):

<svg x = "10" y = 20 "width ="100 "height ="150">

嵌套视口:
在嵌套视口中,(VP_min_X, VP_min_Y)定义了相对于VCS原点的缩进:

<svg width="100%" height="100%"> <!-- external viewport = full browser size -->
     <svg x="50" y="100" width="200" height="300" viewBox="0 0 100 100">
     </svg>
</svg>

在这种情况下,嵌套视口的缩进为:
从外部 VCS 的原点沿 X 轴偏移 50px,沿 Y 轴偏移 100px。

决定 SVG 图形将被绘制的矩形区域(视口)的尺寸如下:

  • VP_width
  • VP_height

VIEWBOX 设置:
当地坐标系(LCS)的原点为:

  • Vb_min_X
  • Vb_min_y

SVG 图像可见部分的尺寸:

  • Vb_width
  • Vb_height

渲染:
在构建最终的 SVG 图像时,通过组合以下内容来转换坐标系:
坐标系的原点:

  • VCS (VP_min_X, VP_min_Y)
  • LCS (VB_min_X, VB_min_Y)

可见图像区域的端点:

  • VCS (VP_width, VP_height)
  • LCS (VB_width, VB_height)

能力:
结果,可以控制以下内容:

  • 视口在浏览器窗口中的位置(使用嵌套视口并更改 (VP_min_X, VP_min_Y))
  • 视口大小(VP_width、VP_height)
  • 平移图像的可见部分(使用 viewBox 并更改 (VB_min_X, VB_min_Y))
  • 缩放图像的可见部分(使用 viewBox 并更改 (VB_width, VB_height))

可视化: 在 YouTube 上花费 2 分钟了解以上原则:
video viewBox in SVG

文档:
W3C 2019 SVG 2 规范


3

以下是一些实用信息,我认为了解SVG视口和视图框架(viewPort 和 viewBox)尤其有助于工作。

SVG使用视口和视图框架这两个术语。视图框架位于视口之内。将视图框架视为图像本身,因为您可以在视口内缩放、向左/右或上/下滑动它。视口(即SVG标签本身)就像一个容器,其中包含SVG图像。您还可以调整并移动此容器的大小。而SVG标签则位于HTML容器(div、p、aside、h3等)中。因此,人们通常会觉得视口/viewBox有点令人困惑。只需将viewBox视为图像本身即可。

SVG标签上的width/height属性提供了视口的大小。这是显示SVG图像的容器的宽度/高度。 (您也可以有x=""和y=""属性,就像在viewBox属性中一样。)

所以,在SVG本身上,您需要指定width / height和起始的x偏移量/ y偏移量 - 这些被称为视口(也称为ViewPort Coord System)。在viewBox属性中,您需要指定"x y width height" - 这些被称为viewBox(也称为局部坐标系 LSC)

<svg x="0" y="0" width="500" height="300"
  viewBox="start_x  start_y  width  height" >
  ...path fill d etc...
</svg>

重要概念 #1:视口的宽度 / 高度(指 SVG 标签本身的 width="" 和 height="")指定了 SVG 图像将要显示的容器大小。通常情况下,如果省略这些属性,容器大小会精确地与 SVG 图像本身的大小相同或稍微大一点。
超级重要概念 #2:视图框的宽度 / 高度直接关联到视口的宽度 / 高度。如果视口是 300 x 500,那么当视图框 W / H 数字变得比 300 x 500 更大时,图像本身会在视口内缩小(缩小)。但是当视图框的 w/h 变小于 300 x 500 时,图像本身会在视口内变大。这种增长是向右和向下的,因此如果你需要在现在太小的视口中滑动缩放后的图像,那么就需要使用 viewBox 的 X / Y 值。
viewBox x/y - 在视口内将 SVG 向右 / 向下滑动
viewBox width/height - 当 viewBox 的宽度 / 高度增加大于 SVG 标签的宽度 / 高度时,在视口内将图像缩小。SVG 在视口内向右 / 向下缩小。将数字减小至小于 SVG 宽度 / 高度属性:图像将在视口内增大,直到图像的右侧 / 底部被视口的右侧 / 底部遮挡。*(即当 viewBox 属性中的宽度 / 高度数字小于 SVG 上的宽度 / 高度属性时,图像在视口内缩放。当数字更大时,图像在视口内缩小。
viewPort x/y == 在其 HTML 容器中将视口本身向右 / 向下滑动 viewPort width/height - 调整整个视口的大小,可能超出 HTML 容器(div / p / 等)。基本上,通过向右 / 向下增长来使视口变大。

注意:
a. 如果在SVG上不包含ViewBox属性,则viewBox的大小等于视口(占据视口的100%)
b. 如果视图框起始于0,0并且与SVG宽度/高度相同(即视口),则不会发生任何变化。相当于根本没有视图框属性。
c. 如果你的视口大小是一副牌的大小,但是SVG图像的大小是一个麦片盒子的大小,那么增加"xy..."数值将使麦片盒图像在视口中向上/向左移动,展示麦片盒图像的另一部分。这对于sprites很有用。
d. (通常(总是!)SVG元素也在HTML容器内 - 例如div、p、section、li等。我们没有讨论过这个问题,但请记住这一点。如果你的图像被裁剪了,那么可能是因为viewBox大于视口或HTML容器元素(div等)小于视口)

以下是两个(精彩的!)短视频,由本主题内的答案作者推荐:

2分钟视频演示
5分钟视频演示(同一人,更好)


1

这里有一个非技术性的方法来说明宽度、高度和viewBox之间的关系:

如果你在电脑上有一张尺寸为1500 x 1000的旧图像,并且你捏住图像的角并把它缩放到300 x 200,那么图像就会缩小或缩放(假设启用了缩放功能)。反之亦然。

一个好的经验法则是首先查看viewBox的宽度和高度,并将其与SVG的宽度和高度(或父元素的宽度和高度,如果它们没有在SVG中声明)进行比较。这样你就可以知道SVG图像是否会放大(增长)或缩小(收缩)。

<svg width="300px" height="200px" viewBox="0 0 1500 1000">

上面的代码告诉浏览器你有一个SVG图像,它的尺寸为1500 x 1000,但你想要它“挤压角落”并将其缩小到300 x 200。

0

viewbox 是一个比例

根据我的经验,我一直认为 <svg>viewbox 值是必需的图像比例,以应用于 widthheight 值。虽然像处理 DOM 中的任何 <img> 一样定义后者,可以通过内联 HTML 属性或通过 CSS 进行,但 viewbox 属性仅适用于 SVG 文件。


你能把 viewbox 改成 viewBox,用大写的 B 吗?由于某种奇怪的原因,这个属性名是大小写敏感的,而且(令人奇怪的是)与其他属性名(如 stroke-width)不同,没有连字符。 - Cristian

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