如何使用 < svg > viewBox 属性?

我从它的官方文件中了解到 svg,有这样的线。我不明白,如果它已经有了 widthheight属性,那么在 viewBox="0 0 1500 1000"中再次指定它有什么意义呢? 它说,“一个 px 单位被定义为等于一个用户单位。因此,“5px”的长度和官方文档中的“5”的长度是一样的,所以这个 viewBox 的宽度是1500px,高度是1000,超过了300px 和200px。那么为什么首先要定义宽度和高度值呢?

 <svg width="300px" height="200px" version="1.1"
viewBox="0 0 1500 1000" preserveAspectRatio="none"
xmlns="http://www.w3.org/2000/svg">
63918 次浏览

The width and height are how big the <svg> is. The viewBox controls how its contents are displayed so the viewBox="0 0 1500 1000" will scale down the contents of <svg> element by a factor of 5 (1500 / 300 = 5 and 1000 / 200 = 5) and the contents will be 1/5 the size they would be without the viewBox but the <svg>

Imagine you have an elastic surface and cut it into 4 equal pieces. If you throw 3 pieces away you've got a surface that's 1/4 the size of the original surface. If you now stretch the surface and make it the same size as the original surface then everything on the surface will be twice the size. That's how viewBox and width/height are related.

If you don't specify a viewbox, all unitless numbers in an element are assumed to be pixels. (and SVG assumes 90 dpi or pixels per inch for conversion from units like cm to pixels.)

A viewbox lets you make unitless numbers in elements mean "user units" and specifies how those units are mapped to the size. For simplicity, consider just the x coordinates, that is, a ruler. Your viewbox says that your ruler will have 1500 units to match the 200 pixel size width of the svg.

A line element from 0 to 1500 (unitless, i.e. user units) would stretch 200 pixels as drawn, that is, across the width of the svg drawing.

(And since SVG is scalable without loss of resolution, pixels really don't mean much in the real world, when a user zooms in or out.)

Its a coordinate transformation, of sorts.

I suggest you learn from a book like "SVG Essentials", about $10 used, from which I loosely quote this answer.

By default

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

the "ruler" of svg grid is in pixel (all shapes in that svg is measured in pixel)

But you want to use your own units you can use viewBox attr for that:

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

That means:

horizontal axis: 1500 (your width unit) = 300px => 1 (your width unit) = 300/1500px = 1/5px

vertical axis: 1000 (your height unit) = 200px => 1 (your height unit) = 200/1000px = 1/5px

  • Now all shapes in the svg will scale:

their widths scale to 1/5px (1/5 < 1 => scale down) comparing to the origin.

their heights also scale to 1/5px (1/5 < 1 => scale down) comparing to the origin

MAIN:

  • The viewBox attribute is closely related to the term viewport in SVG

ABBREVIATION:

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

SYNTAX:

<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">


DEFAULT VALUES:

  • units = px
  • viewport width = 300
  • viewport width = 150
  • viewBox = viewport

CODE WITH DEFAULT VALUES

<svg>

CODE WITH THE SAME RESULT:

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

VIEWPORT SETTINGS:
THE ORIGIN POINT of the viewport coordinate system (VCS):

  • VP_min_X
  • VP_min_Y

in the case of the outermost viewport, these values do not matter and in any case will be equal to 0, they are usually omitted:

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

CODE WITH THE SAME RESULT: (for the most external viewport):

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

NESTED VIEWPORT:
In a nested viewport (VP_min_X, VP_min_Y) define the indent from the origin point of 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>

in this case indent of the nested viewport:
50px along the X axis and 100px along the Y axis from the origin point of the external VCS.

THE DIMENSIONS of the rectangular area (viewport) in which SVG grafics will be drawn are determined:

  • VP_width
  • VP_height

VIEWBOX SETTINGS:
THE ORIGIN POINT of the local coordinate system (LCS):

  • Vb_min_X
  • Vb_min_y

THE SIZE of the visible part of the SVG image:

  • Vb_width
  • Vb_height

RENDERING:
When constructing the final SVG image, the coordinate systems are transformed by COMBINING:
Points of origin of coordinate systems:

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

End points of the visible image area:

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

CAPABILITIES:
As a result, it becomes possible to control:

  • location of the viewport in the browser window [using the nested viewport and changing (VP_min_X, VP_min_Y)]
  • viewport sizes (VP_width, VP_height)
  • panning the visible part of the image [using viewBox and changing (VB_min_X, VB_min_Y)]
  • scaling the visible part of the image [using viewBox and changing (VB_width, VB_height)]

VISUALIZATION: 2 minutes on YouTube to understand the principles described above:
video viewBox in SVG

DOCUMENTATION:
W3C 2019 SVG 2 specification

viewbox is a ratio

In my humble experience, I've always considered <svg>’s viewbox values as a required image ratio to apply to the width and height values. While defining the laters just I do with any <img> in the DOM, either inline HTML properties or via CSS, viewbox property only applies to the SVG file.

Here is some practical information that I find useful to understand (and particularly to work with) SVG viewPort and viewBox.

SVG uses the terms viewPort and viewBox. The viewBox is inside the viewPort. Think of the viewBox as the image itself – because you can zoom it, slide it left/right/up/down – all within the viewPort. The viewPort (the SVG tag itself) is like a container that the SVG image is inside. You can size this also, and move it around left/right/up/down. And the SVG tag is within an HTML container (div, p, aside, h3, etc). So you can see why people find viewPort / viewBox to be a bit confusing. Just think of viewBox as the image itself.

The width/height attributes on the SVG tag provide the size of the viewPort. This is the width/height of the container in which the SVG image is displayed. (You can also have ABC0 and y="" attributes, just as you have in the viewBox attribute.)

So, on the SVG itself, you specify width /height and starting x offset / starting y offset – these are called the viewPort (aka ViewPort Coord System) In the viewBox attribute, you specify "x y width height" – these are called the viewBox (aka Local Coord System LCS)

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

Important Concept #1: the width/height of the viewPort (the ones that are on the SVG tag itself, as width="" and height="") specify the size of the container in which the SVG image will be displayed. Usually, or if omitted, this is the exact size as (or a tiny bit larger than) the SVG image itself.

Super-Important Concept #2: the width/height of the viewBox is directly related to the width/height of the viewPort. If the viewPort is 300 x 500, then as the viewBox W / H numbers get LARGER than 300 x 500, the image itself grows smaller within the viewPort (zooms out). But as the viewBox w/h gets smaller than 300 x 500, the image itself grows LARGER within the viewPort. This growth is to the right and down, so if you need to slide the zoomed-in image around in the now-too-small viewPort, that is when you use the X / Y values of the viewBox.

viewBox x/y – slides the SVG right/down inside the viewPort

viewBox width/height – as increase larger than the SVG tag's width/height, it zooms the image OUT inside the viewPort. The SVG shrinks right/down within the viewport. Decrease number below the SVG width/height attribs: the image will GROW in the viewport until portions of the image to the right/bottom may be cut off by the rightSide/Bottom of the viewPort. *(i.e. when the width/height numbers in the viewBox attribute are less than the width/height attributes on the SVG, the image ZOOMS IN within the viewPort. When larger, the image zooms OUT (shrinks) with the viewPort.

viewPort x/y == slides the viewport itself right/down within its HTML container viewPort width/height – resizes the entire viewPort larger, possibly overflowing the HTML container (div / p / etc). Basically, makes the viewPort larger by growing it right/down.

Notes:
a. If you do not include the ViewBox attribute on the SVG, then the size of the viewBox equals the size of the viewPort (takes 100% of the viewPort)
b. If the viewBox begins 0,0 and has same width/height as the SVG width/height (i.e. the viewPort), nothing will change. Equivalent to not having a viewbox attribute at all.
c. If you have a viewPort the size of a deck of cards, but the SVG image is the size of a cereal box, then increasing the viewBox "x y …" numbers will move the cereal box image up/left in the viewPort, showing a different part of the cereal box's image. This would be useful with sprites
d. (Usually (always!) the SVG element is also inside an HTML container - a div, p, section, li, whatever. We didn't discuss this, but remember it. If your image is being cut off, then either the viewBox is larger than the viewPort -OR- the HTML container element (div, etc) is smaller than the viewPort)

Here are two (excellent!) short videos, referred to us by the author of this answer within this same thread:

2min video demo
5min video demo (same guy, much better)

Here's a non-technical way of illustrating the relationship between width, height and the viewBox:

If you had any old image on your computer with the dimensions 1500 x 1000, and you pinched the corner of the image and resized it to 300 x 200, the image would shrink, or scale down (assuming scaling is enabled). The opposite is also true.

A good rule of thumb is to always look at the viewBox width and height first, and compare it to the SVG's width and height (or the parent's width and height if they are not declared in the SVG). That way you can tell whether the SVG image will scale up (grow), or down (shrink).

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

The above is telling the browser that you have an SVG that's 1500 x 1000 but you want it to "pinch the corners" and shrink it down to 300 x 200.