SVG 内容的内在大小属性

Posted

技术标签:

【中文标题】SVG 内容的内在大小属性【英文标题】:Intrinsic sizing properties of SVG content 【发布时间】:2019-03-08 08:20:32 【问题描述】:

我正在努力解决 SVG 元素的固有大小问题。

根据 SVG 规范,8.12. Intrinsic sizing properties of SVG content 章,我们知道:

为了在使用 CSS 格式化的宿主文档中包含 SVG, 必须计算具体对象的大小。具体对象大小必须 使用默认大小算法计算

作为默认大小算法的输入,我们在同一部分中读到:

指定的尺寸必须根据使用的值确定 “svg”元素的宽度和高度尺寸属性。

还有:

内在尺寸也必须由宽度和 高度尺寸属性。如果未指定宽度或高度, 使用的值是初始值'auto'。 'auto' 和百分比 不得使用长度来确定内在宽度或内在 高度。

所以,如果我们没有在最外层的 svg 元素上设置 widthheight,我们就有 固有尺寸 (width / height)为auto(含糊地建议不要这样做)。 Default Sizing Algorithm的相关部分:

如果指定的尺寸没有约束(没有宽/高):

    如果对象具有固有高度或宽度,则解析其大小 就好像它的内在大小被指定为指定大小一样。 否则,其大小将被解析为针对默认对象大小的包含约束

最后来自8.3. The initial viewport:

初始视口的宽度,必须是宽度的值 最外层 svg 元素上的presentation 属性...

尽管上面有第一个粗体警告,在最外层的 svg 元素上定义 widthheight 表示属性是正常的。 Adobe Illustrator 等程序通常会忽略这些属性,而只是定义一个 viewBox

所以我的问题是:

如果没有设置 widthheight 属性,我可以在规范中的何处找到 svg 元素使用的 widthheight 将是什么有吗?

同样,在同样的场景中,viewport 的尺寸会是多少(仅给定一个 svg 元素)?


附带说明,来自 css-sizing-3 4. Intrinsic Size Determination:

对于具有固有纵横比但没有固有大小的框:

如果内联轴上的可用空间是确定的,则使用拉伸 适合内联大小的大小并计算块大小 使用纵横比。


一些代码

展示了我无法理解的行为(即在两种 flexbox 情况下如何计算尺寸)。

注意:当布局为列时,弹性项目的宽度为零。 (这与 SVG 有关,与 flexbox 无关)。

.c1,
.c2 
  display: flex;
  height: 500px;
  align-items: flex-start;


.c1 
  flex-flow: row nowrap;
  border: 1px solid green;


.c1 .i1 
  flex: 0 1 100px;
  border: 1px solid blue;


.c2 
  flex-flow: column nowrap;
  border: 1px solid green;


.c2 .i2 
  flex: 0 1 100px;
  border: 1px solid red;
<div class="c1">
  <div class="i1">
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 300 300">
      <defs>
        <g id="SVG" fill="#fff" transform="scale(2) translate(20,79)">
	<path id="S" d="M 5.482,31.319 C2.163,28.001 0.109,23.419 0.109,18.358 C0.109,8.232 8.322,0.024 18.443,0.024 C28.569,0.024 36.782,8.232 36.782,18.358 L26.042,18.358 C26.042,14.164 22.638,10.765 18.443,10.765 C14.249,10.765 10.850,14.164 10.850,18.358 C10.850,20.453 11.701,22.351 13.070,23.721 L13.075,23.721 C14.450,25.101 15.595,25.500 18.443,25.952 L18.443,25.952 C23.509,26.479 28.091,28.006 31.409,31.324 L31.409,31.324 C34.728,34.643 36.782,39.225 36.782,44.286 C36.782,54.412 28.569,62.625 18.443,62.625 C8.322,62.625 0.109,54.412 0.109,44.286 L10.850,44.286 C10.850,48.480 14.249,51.884 18.443,51.884 C22.638,51.884 26.042,48.480 26.042,44.286 C26.042,42.191 25.191,40.298 23.821,38.923 L23.816,38.923 C22.441,37.548 20.468,37.074 18.443,36.697 L18.443,36.692 C13.533,35.939 8.800,34.638 5.482,31.319 L5.482,31.319 L5.482,31.319 Z"/>
	<path id="V" d="M 73.452,0.024 L60.482,62.625 L49.742,62.625 L36.782,0.024 L47.522,0.024 L55.122,36.687 L62.712,0.024 L73.452,0.024 Z"/>
	<path id="G" d="M 91.792,25.952 L110.126,25.952 L110.126,44.286 L110.131,44.286 C110.131,54.413 101.918,62.626 91.792,62.626 C81.665,62.626 73.458,54.413 73.458,44.286 L73.458,44.286 L73.458,18.359 L73.453,18.359 C73.453,8.233 81.665,0.025 91.792,0.025 C101.913,0.025 110.126,8.233 110.126,18.359 L99.385,18.359 C99.385,14.169 95.981,10.765 91.792,10.765 C87.597,10.765 84.198,14.169 84.198,18.359 L84.198,44.286 L84.198,44.286 C84.198,48.481 87.597,51.880 91.792,51.880 C95.981,51.880 99.380,48.481 99.385,44.291 L99.385,44.286 L99.385,36.698 L91.792,36.698 L91.792,25.952 L91.792,25.952 Z"/>
        </g>
      </defs>
      <path id="base" fill="#000" d="M8.5,150 H291.5 V250 C291.5,273.5 273.5,291.5 250,291.5 H50 C26.5,291.5 8.5,273.5 8.5,250 Z"/>
      <g stroke- stroke="#000">
        <g id="svgstar" transform="translate(150, 150)">
          <path id="svgbar" fill="#ffb13b" d="M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z"/>
          <use xlink:href="#svgbar" transform="rotate(45)"/>
          <use xlink:href="#svgbar" transform="rotate(90)"/>
          <use xlink:href="#svgbar" transform="rotate(135)"/>
        </g>
      </g>
      <use xlink:href="#svgstar"/>
      <use xlink:href="#base" opacity="0.85"/>
      <use xlink:href="#SVG"/>
    </svg>
  </div>
</div>


<div class="c2">
  <div class="i2">
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 300 300">
      <defs>
        <g id="SVG" fill="#fff" transform="scale(2) translate(20,79)">
	<path id="S" d="M 5.482,31.319 C2.163,28.001 0.109,23.419 0.109,18.358 C0.109,8.232 8.322,0.024 18.443,0.024 C28.569,0.024 36.782,8.232 36.782,18.358 L26.042,18.358 C26.042,14.164 22.638,10.765 18.443,10.765 C14.249,10.765 10.850,14.164 10.850,18.358 C10.850,20.453 11.701,22.351 13.070,23.721 L13.075,23.721 C14.450,25.101 15.595,25.500 18.443,25.952 L18.443,25.952 C23.509,26.479 28.091,28.006 31.409,31.324 L31.409,31.324 C34.728,34.643 36.782,39.225 36.782,44.286 C36.782,54.412 28.569,62.625 18.443,62.625 C8.322,62.625 0.109,54.412 0.109,44.286 L10.850,44.286 C10.850,48.480 14.249,51.884 18.443,51.884 C22.638,51.884 26.042,48.480 26.042,44.286 C26.042,42.191 25.191,40.298 23.821,38.923 L23.816,38.923 C22.441,37.548 20.468,37.074 18.443,36.697 L18.443,36.692 C13.533,35.939 8.800,34.638 5.482,31.319 L5.482,31.319 L5.482,31.319 Z"/>
	<path id="V" d="M 73.452,0.024 L60.482,62.625 L49.742,62.625 L36.782,0.024 L47.522,0.024 L55.122,36.687 L62.712,0.024 L73.452,0.024 Z"/>
	<path id="G" d="M 91.792,25.952 L110.126,25.952 L110.126,44.286 L110.131,44.286 C110.131,54.413 101.918,62.626 91.792,62.626 C81.665,62.626 73.458,54.413 73.458,44.286 L73.458,44.286 L73.458,18.359 L73.453,18.359 C73.453,8.233 81.665,0.025 91.792,0.025 C101.913,0.025 110.126,8.233 110.126,18.359 L99.385,18.359 C99.385,14.169 95.981,10.765 91.792,10.765 C87.597,10.765 84.198,14.169 84.198,18.359 L84.198,44.286 L84.198,44.286 C84.198,48.481 87.597,51.880 91.792,51.880 C95.981,51.880 99.380,48.481 99.385,44.291 L99.385,44.286 L99.385,36.698 L91.792,36.698 L91.792,25.952 L91.792,25.952 Z"/>
        </g>
      </defs>
      <path id="base" fill="#000" d="M8.5,150 H291.5 V250 C291.5,273.5 273.5,291.5 250,291.5 H50 C26.5,291.5 8.5,273.5 8.5,250 Z"/>
      <g stroke- stroke="#000">
        <g id="svgstar" transform="translate(150, 150)">
          <path id="svgbar" fill="#ffb13b" d="M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z"/>
          <use xlink:href="#svgbar" transform="rotate(45)"/>
          <use xlink:href="#svgbar" transform="rotate(90)"/>
          <use xlink:href="#svgbar" transform="rotate(135)"/>
        </g>
      </g>
      <use xlink:href="#svgstar"/>
      <use xlink:href="#base" opacity="0.85"/>
      <use xlink:href="#SVG"/>
    </svg>
  </div>
</div>

【问题讨论】:

对于 SVG 等待 ***.com/users/1038015/robert-longson 他肯定会得到答案 ;) 我觉得这将以 flexbox 问题结束 嘿嘿嘿@temaniafif!我不这么认为,因为如果你删除两个 svg 项目,你会看到交叉轴折叠到 0 大小,正如 flexbox 所预期的那样,当 align-items 没有拉伸时。当您在每个中引入 SVG 时,两者突然开始表现不同。方向:列的宽度仍保持为 0,但高度尊重方向:行的 svg 纵横比。对此完全感到困惑。 svg 规范是巨大的 我发现这篇文章对于理解 SVG 坐标和调整大小特别有用 sarasoueidan.com/blog/svg-coordinate-systems 如果你添加这个 css 块会变得非常有趣:svg width: auto; height: 100%; 如果你调整窗口大小,SVG 将会增长。 【参考方案1】:

body 
  box-sizing: border-box;


.c1 
  display: flex;
  flex-flow: column nowrap;


.c1 .i1 
  flex: 0 1 100px;
  border: 1px solid red;


.c2 
  display: flex;
  flex-flow: row nowrap;


.c2 .i2 
  flex: 0 1 100px;
  border: 1px solid blue;
<div class="c2">
  <div class="i2">
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 300 300">
      <defs>
        <g id="SVG" fill="#fff" transform="scale(2) translate(20,79)">
	<path id="S" d="M 5.482,31.319 C2.163,28.001 0.109,23.419 0.109,18.358 C0.109,8.232 8.322,0.024 18.443,0.024 C28.569,0.024 36.782,8.232 36.782,18.358 L26.042,18.358 C26.042,14.164 22.638,10.765 18.443,10.765 C14.249,10.765 10.850,14.164 10.850,18.358 C10.850,20.453 11.701,22.351 13.070,23.721 L13.075,23.721 C14.450,25.101 15.595,25.500 18.443,25.952 L18.443,25.952 C23.509,26.479 28.091,28.006 31.409,31.324 L31.409,31.324 C34.728,34.643 36.782,39.225 36.782,44.286 C36.782,54.412 28.569,62.625 18.443,62.625 C8.322,62.625 0.109,54.412 0.109,44.286 L10.850,44.286 C10.850,48.480 14.249,51.884 18.443,51.884 C22.638,51.884 26.042,48.480 26.042,44.286 C26.042,42.191 25.191,40.298 23.821,38.923 L23.816,38.923 C22.441,37.548 20.468,37.074 18.443,36.697 L18.443,36.692 C13.533,35.939 8.800,34.638 5.482,31.319 L5.482,31.319 L5.482,31.319 Z"/>
	<path id="V" d="M 73.452,0.024 L60.482,62.625 L49.742,62.625 L36.782,0.024 L47.522,0.024 L55.122,36.687 L62.712,0.024 L73.452,0.024 Z"/>
	<path id="G" d="M 91.792,25.952 L110.126,25.952 L110.126,44.286 L110.131,44.286 C110.131,54.413 101.918,62.626 91.792,62.626 C81.665,62.626 73.458,54.413 73.458,44.286 L73.458,44.286 L73.458,18.359 L73.453,18.359 C73.453,8.233 81.665,0.025 91.792,0.025 C101.913,0.025 110.126,8.233 110.126,18.359 L99.385,18.359 C99.385,14.169 95.981,10.765 91.792,10.765 C87.597,10.765 84.198,14.169 84.198,18.359 L84.198,44.286 L84.198,44.286 C84.198,48.481 87.597,51.880 91.792,51.880 C95.981,51.880 99.380,48.481 99.385,44.291 L99.385,44.286 L99.385,36.698 L91.792,36.698 L91.792,25.952 L91.792,25.952 Z"/>
        </g>
      </defs>
      <path id="base" fill="#000" d="M8.5,150 H291.5 V250 C291.5,273.5 273.5,291.5 250,291.5 H50 C26.5,291.5 8.5,273.5 8.5,250 Z"/>
      <g stroke- stroke="#000">
        <g id="svgstar" transform="translate(150, 150)">
          <path id="svgbar" fill="#ffb13b" d="M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z"/>
          <use xlink:href="#svgbar" transform="rotate(45)"/>
          <use xlink:href="#svgbar" transform="rotate(90)"/>
          <use xlink:href="#svgbar" transform="rotate(135)"/>
        </g>
      </g>
      <use xlink:href="#svgstar"/>
      <use xlink:href="#base" opacity="0.85"/>
      <use xlink:href="#SVG"/>
    </svg>
  </div>
</div>


<div class="c1">
  <div class="i1">
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 300 300">
      <defs>
        <g id="SVG" fill="#fff" transform="scale(2) translate(20,79)">
	<path id="S" d="M 5.482,31.319 C2.163,28.001 0.109,23.419 0.109,18.358 C0.109,8.232 8.322,0.024 18.443,0.024 C28.569,0.024 36.782,8.232 36.782,18.358 L26.042,18.358 C26.042,14.164 22.638,10.765 18.443,10.765 C14.249,10.765 10.850,14.164 10.850,18.358 C10.850,20.453 11.701,22.351 13.070,23.721 L13.075,23.721 C14.450,25.101 15.595,25.500 18.443,25.952 L18.443,25.952 C23.509,26.479 28.091,28.006 31.409,31.324 L31.409,31.324 C34.728,34.643 36.782,39.225 36.782,44.286 C36.782,54.412 28.569,62.625 18.443,62.625 C8.322,62.625 0.109,54.412 0.109,44.286 L10.850,44.286 C10.850,48.480 14.249,51.884 18.443,51.884 C22.638,51.884 26.042,48.480 26.042,44.286 C26.042,42.191 25.191,40.298 23.821,38.923 L23.816,38.923 C22.441,37.548 20.468,37.074 18.443,36.697 L18.443,36.692 C13.533,35.939 8.800,34.638 5.482,31.319 L5.482,31.319 L5.482,31.319 Z"/>
	<path id="V" d="M 73.452,0.024 L60.482,62.625 L49.742,62.625 L36.782,0.024 L47.522,0.024 L55.122,36.687 L62.712,0.024 L73.452,0.024 Z"/>
	<path id="G" d="M 91.792,25.952 L110.126,25.952 L110.126,44.286 L110.131,44.286 C110.131,54.413 101.918,62.626 91.792,62.626 C81.665,62.626 73.458,54.413 73.458,44.286 L73.458,44.286 L73.458,18.359 L73.453,18.359 C73.453,8.233 81.665,0.025 91.792,0.025 C101.913,0.025 110.126,8.233 110.126,18.359 L99.385,18.359 C99.385,14.169 95.981,10.765 91.792,10.765 C87.597,10.765 84.198,14.169 84.198,18.359 L84.198,44.286 L84.198,44.286 C84.198,48.481 87.597,51.880 91.792,51.880 C95.981,51.880 99.380,48.481 99.385,44.291 L99.385,44.286 L99.385,36.698 L91.792,36.698 L91.792,25.952 L91.792,25.952 Z"/>
        </g>
      </defs>
      <path id="base" fill="#000" d="M8.5,150 H291.5 V250 C291.5,273.5 273.5,291.5 250,291.5 H50 C26.5,291.5 8.5,273.5 8.5,250 Z"/>
      <g stroke- stroke="#000">
        <g id="svgstar" transform="translate(150, 150)">
          <path id="svgbar" fill="#ffb13b" d="M-84.1487,-15.8513 a22.4171,22.4171 0 1 0 0,31.7026 h168.2974 a22.4171,22.4171 0 1 0 0,-31.7026 Z"/>
          <use xlink:href="#svgbar" transform="rotate(45)"/>
          <use xlink:href="#svgbar" transform="rotate(90)"/>
          <use xlink:href="#svgbar" transform="rotate(135)"/>
        </g>
      </g>
      <use xlink:href="#svgstar"/>
      <use xlink:href="#base" opacity="0.85"/>
      <use xlink:href="#SVG"/>
    </svg>
  </div>
</div>

"The ‘viewBox’ attribute, in conjunction with the ‘preserveAspectRatio’ attribute, provides the capability to stretch an SVG viewport to fit a particular container element."。

.i2 元素的宽度约为 100 像素。内部的 svg 会缩放以适应可用的宽度。

.i1 元素的宽度是可用空间的 100%。内部的 svg 缩放以适应 .i1 的可用宽度。

.i1.i2 元素的宽度由 flexbox 布局决定。如果您删除 .i1.i2 元素中的 svg:

.i2 将折叠:默认情况下,空元素的高度为 0。其宽度为 100px(由 flex 基础确定) .i1 不会折叠,因为它的高度由 flex 基础 (100px) 确定,而宽度默认为 100%。

【讨论】:

enxaneta,感谢您帮助我了解这一点。我修改了代码,您引用的类仍然正确吗?所有容器(.c)都不是 100px,只有项目(.i) 另请注意:i2 折叠为 0 宽度,即使里面有一个 svg 元素 嗯,这里发生了一些奇怪的事情。我的代码显示了一个完全折叠的 i2(它的顺序与您的答案不同)。我在想,当您复制 sn-p 时,我可能还没有完成编辑?可能是 align-items 使它伸展。 这里奇怪的是,在行的情况下,调整高度以尊重 flex-basis 的宽度。换句话说,高度是根据纵横比和宽度值计算的。然而,在列的情况下, flex-basis 设置 100px 高度,但宽度不是根据纵横比和高度值计算的。我不完全明白为什么一个人的行为与另一个人不同。 PS:除非我打错字,否则 i2 不是 flex 容器。它是一个弹性项目(.c 是容器)。哈哈,呃,这似乎是我正在尝试做的一项常见任务,但很难弄清楚它实际上是如何工作的。【参考方案2】:

SVG 元素被视为替换元素,并遵守 300px x 150px 大小的替换元素的规则。

您可以在 CSS3 规范中找到相关的规范语言:

https://www.w3.org/TR/css-sizing-3/

对于没有固有纵横比的盒子:如果可用空间是 在适当的尺寸确定,使用拉伸配合到那个 尺寸。

否则,如果盒子有一个明确的非零最小尺寸 (min-width/min-height) 在那个维度,使用那个大小。

否则,使用 300px 作为宽度和/或 150px 作为高度 需要。

【讨论】:

迈克尔,谢谢。但是 svg 项目确实有一个纵横比,由它的 viewBox 定义。我不清楚为什么当 svg 放在里面时,列布局中的宽度会折叠为 0。高度是给定的,所以 svg 项目应该设置自己的宽度以保持它的纵横比(因为高度是在 img 标签上设置的),宽度应该强制 SVG 的容器(flex 项目)调整其宽度。

以上是关于SVG 内容的内在大小属性的主要内容,如果未能解决你的问题,请参考以下文章

如何摆脱告诉我将 svg 属性更改为驼峰式大小写的反应错误警告?

调整大小时 SVG 图像质量下降

按比例禁用 SVG 自动缩放

矢量图

SVG文本

如何获得 SVG 组元素的高度/宽度?