缩放 SVG 背景

鉴于 SVG 图像的灵活性,当使用 background-image 属性将其用作背景图像时,需要考虑很多问题,而当使用 background-size 属性对其进行缩放时,需要考虑的问题就更多了。本文将介绍在使用这些属性时,SVG 图像的缩放是如何处理的。

背景尺寸调整算法

用于确定背景图像尺寸的算法,在很大程度上可以用以下四条规则来概括。有一些边缘情况未被这些规则覆盖,但这已经涵盖了大多数情况。

  1. 如果 background-size 指定了一个固定的尺寸(即百分比和相对单位由其上下文确定),则该尺寸优先。
  2. 如果图像具有固有比例(intrinsic ratio)(即其宽高比是固定的,如 16:9、4:3、2.39:1、1:1 等),则渲染尺寸会保持该比例。
  3. 如果图像指定了尺寸,且该尺寸未被 constraincover 修改,则指定的尺寸优先。
  4. 如果以上情况均不满足,则图像将以与背景区域相同的尺寸进行渲染。

值得注意的是,背景尺寸调整算法只关心图像的尺寸和比例,或者说它们是否存在。一个具有固定尺寸的 SVG 图像将被视为与同尺寸的光栅图像一样。

备注: 如果你尝试用 CSS 将 SVG 拉伸到不同的宽高比——例如为了将其拉伸以覆盖整个页面背景——请确保你的 SVG 包含 preserveAspectRatio="none"。了解更多关于 preserveAspectRatio 的信息。

源图像示例

在深入研究使用不同类型的 SVG 源图像并观察它们与 background-size 结合使用的效果之前,先看几个具有不同尺寸和大小设置的源图像示例会很有帮助,我们稍后将在示例中将它们用作 background-image 的值。浏览器默认将 <svg> 图像渲染为 300px 宽和 150px 高。

无尺寸和无比例

这个 SVG 渐变图像既没有尺寸也没有比例。它不关心自身的大小,也不关心是否保持特定的宽高比。这可以作为一个很好的渐变桌面背景,无论你的屏幕尺寸和宽高比如何都能正常工作。

html
<svg>
  <title>Corner-to-corner gradient</title>
  <defs>
    <linearGradient id="g" x1="0%" x2="100%" y1="0%" y2="100%">
      <stop stop-color="pink" offset="0" />
      <stop stop-color="goldenrod" offset="1" />
    </linearGradient>
  </defs>
  <rect fill="url('#g')" width="100%" height="100%" />
</svg>

指定了一个维度且无比例

这个图像指定了 100 像素的宽度,但没有指定高度或固有比例。这基本上就像一条薄薄的壁纸,可以拉伸到整个块的高度。

html
<svg width="100">
  <title>Vertical gradient, with a fixed width</title>
  <defs>
    <linearGradient id="g" x1="0%" x2="0%" y1="0%" y2="100%">
      <stop stop-color="purple" offset="0" />
      <stop stop-color="lime" offset="1" />
    </linearGradient>
  </defs>
  <rect fill="url('#g')" width="100%" height="100%" />
</svg>

指定了一个维度并有固有比例

这个图像指定了 100 像素的高度,但没有指定宽度。它还指定了 3:4 的固有宽高比。这确保了它的宽高比始终为 3:4,除非被有意缩放到不成比例的尺寸(即通过明确指定非该比例的宽度和高度)。

这非常类似于同时指定特定的宽度和高度;因为一旦你有了其中一个维度和比例,另一个维度也就被隐含地确定了。

html
<svg height="100" viewBox="0 0 3 4" preserveAspectRatio="none">
  <title>Vertical gradient, with a fixed height and intrinsic ratio</title>
  <defs>
    <linearGradient id="g" x1="0%" x2="0%" y1="0%" y2="100%">
      <stop stop-color="teal" offset="0" />
      <stop stop-color="orange" offset="1" />
    </linearGradient>
  </defs>
  <rect fill="url('#g')" width="100%" height="100%" />
</svg>

无宽度或高度但有固有比例

这个图像没有指定宽度或高度;相反,它指定了 1:1 的固有比例。它始终是正方形,并且可以在任何尺寸下使用,例如 32x32、128x128 或 512x512。

html
<svg viewBox="0 0 1 1" preserveAspectRatio="none">
  <title>Intrinsic ratio</title>
  <defs>
    <linearGradient id="g" x1="0%" x2="100%" y1="0%" y2="0%">
      <stop stop-color="navy" offset="0" />
      <stop stop-color="maroon" offset="1" />
    </linearGradient>
  </defs>
  <rect fill="url('#g')" width="100%" height="100%" />
</svg>

缩放示例

现在让我们看一些例子,看看当我们对这些图像应用不同的缩放时会发生什么。在下面的每个例子中,外围的 <div> 元素都是 300 像素宽和 200 像素高,并带有 2 像素宽的边框。为确保在这些演示中 SVG 背景图像只显示一次,我们将 background-repeat 设置为 no-repeat

css
div {
  width: 300px;
  height: 200px;
  background-repeat: no-repeat;
  border: 2px solid black;
}

为两个维度指定固定长度

如果你使用 background-size 为两个维度指定固定长度,那么根据上述规则 1,这些长度将始终被使用。换句话说,无论源图像是否指定了其尺寸和/或宽高比,图像都将被拉伸到你指定的尺寸。

无尺寸或固有比例

在此示例中,图像未设置尺寸或固有比例。

css
div {
  background-image: url("no-dimensions-or-ratio.svg");
  background-size: 125px 175px;
}

指定了一个维度,无固有比例

在此示例中,图像指定了一个维度,但未设置固有比例。

css
div {
  background-image: url("100px-wide-no-height-or-ratio.svg");
  background-size: 250px 150px;
}

指定了一个维度并有固有比例

在此示例中,图像明确设置了一个维度,并附带了固有比例,这意味着两个维度都得到了有效定义。为 background-size 设置绝对的高度和宽度会覆盖 SVG 中设置的尺寸。

css
div {
  background-image: url("100px-height-3x4-ratio.svg");
  background-size: 275px 125px;
}

未指定宽度或高度,但有固有比例

在此示例中,图像具有固有比例但未设置尺寸。

css
div {
  background-image: url("no-dimensions-1x1-ratio.svg");
  background-size: 250px 100px;
}

使用 contain 或 cover

background-size 指定 cover 会使图片在完全覆盖整个背景区域的同时尽可能小。而 contain 则会使图片在不被背景区域裁剪的情况下尽可能大。

对于具有固有比例的图像,仅凭 cover/fit 条件就能精确匹配一个尺寸。但如果没有指定固有比例,cover/fit 就不够了,因此最终尺寸由最大/最小约束来决定。

无尺寸或固有比例

在此示例中,图像未设置尺寸或固有比例。如果图像既未指定尺寸也未指定固有比例,则规则 2 和规则 3 都不适用,因此规则 4 生效:背景图像被渲染以覆盖整个背景区域。这满足了最大或最小的约束条件。

css
div {
  background-image: url("no-dimensions-or-ratio.svg");
  background-size: contain;
}

指定了一个维度,无固有比例

在此示例中,图像指定了一个维度但没有固有比例,规则 4 适用,图像被缩放以覆盖整个背景区域。

css
div {
  background-image: url("100px-wide-no-height-or-ratio.svg");
  background-size: contain;
}

指定了一个维度并有固有比例

在这些示例中,图像明确设置了一个维度,并附带了固有比例。

当你指定一个固有比例时,情况就变了。在这种情况下,规则 1 不相关,所以应用规则 2:我们尝试保持任何固有比例(同时遵循 containcover)。例如,在一个 300x200 的框中使用 contain 并保持 3:4 的固有宽高比,意味着绘制一个 150x200 的背景。

contain 的情况

给定此 CSS

css
div {
  background-image: url("100px-height-3x4-ratio.svg");
  background-size: contain;
}

请注意整个图像是如何被渲染的,它尽可能地适应框内,而没有任何部分被裁剪掉。

cover 的情况
css
div {
  background-image: url("100px-height-3x4-ratio.svg");
  background-size: cover;
}

在这里,3:4 的比例被保持,同时图像被拉伸以填充整个框。这导致图像的底部被裁剪掉了。

无尺寸但有固有比例

这些示例使用设置了固有比例但没有定义尺寸的图像。当使用没有固有尺寸但有固有比例的图像时,工作方式类似。

contain 的情况
css
div {
  background-image: url("no-dimensions-1x1-ratio.svg");
  background-size: contain;
}

请注意,图像的大小被调整以适应最小的维度,同时保持 1:1 的宽高比。

cover 的情况
css
div {
  background-image: url("no-dimensions-1x1-ratio.svg");
  background-size: cover;
}

在这里,图像的大小被调整以填充最大的维度。1:1 的宽高比得以保持,尽管对于这个源图像来说,这一点可能很难看出来。

对两个维度使用“auto”进行自动调整

如果 background-size 设置为 autoauto auto,规则 2 指出渲染必须保持所提供的任何固有比例。

无尺寸或固有比例

当自动调整未指定固有比例或尺寸的背景图像时,规则 4 生效,图像被渲染以填充背景区域。

css
div {
  background-image: url("no-dimensions-or-ratio.svg");
  background-size: auto auto;
}

一个维度且无固有比例

如果没有指定固有比例,但至少指定了一个维度,则规则 3 生效,我们根据这些维度来渲染图像。

css
div {
  background-image: url("100px-wide-no-height-or-ratio.svg");
  background-size: auto auto;
}

请注意,源 SVG 中指定的 100 像素宽度得到了遵守,而高度则填充了背景区域,因为它未被指定(无论是显式指定还是通过固有比例)。

一个维度和一个固有比例

如果我们有一个固有比例和一个固定的维度,这就固定了两个维度。如前所述,知道一个维度和一个比例等同于明确指定两个维度。

css
div {
  background-image: url("100px-height-3x4-ratio.svg");
  background-size: auto auto;
}

由于此图像的显式高度为 100px。在 SVG 中设置了 3:4 的比例,在 auto 的情况下,图像的宽度为 75 像素。

无固定尺寸但有固有比例

当指定了固有比例但没有指定尺寸时,应用规则 4——除了规则 2 也适用。因此,图像的渲染方式与 contain 的情况相同。

css
div {
  background-image: url("no-dimensions-1x1-ratio.svg");
  background-size: auto auto;
}

使用“auto”和一个特定长度

根据规则 1,指定的尺寸总是被使用,所以我们只需要用我们的规则来确定第二个维度。

无尺寸或固有比例

如果图像没有尺寸或固有比例,则应用规则 4,我们使用背景区域的维度来确定 auto 维度的值。

css
div {
  background-image: url("no-dimensions-or-ratio.svg");
  background-size: auto 140px;
}

在这里,宽度根据规则 4 使用背景区域的宽度来确定,而高度是 CSS 中指定的 140px

指定了一个维度但无固有比例

如果图像指定了一个维度但没有固有比例,并且该维度在 CSS 中设置为 auto,则根据规则 3 使用该指定维度。

css
div {
  background-image: url("100px-wide-no-height-or-ratio.svg");
  background-size: 200px auto;
}

在这里,根据规则 1,CSS 中指定的 200px 覆盖了 SVG 中指定的 100px 宽度。由于没有提供固有比例或高度,auto 会选择背景区域的高度作为渲染图像的高度。

css
div {
  background-image: url("100px-wide-no-height-or-ratio.svg");
  background-size: auto 125px;
}

在这种情况下,宽度在 CSS 中被指定为 auto,因此根据规则 3,选择 SVG 中指定的 100px 宽度。高度在 CSS 中设置为 125px,因此根据规则 1 选择该值。

指定了一个维度并有固有比例

当指定了一个维度时,规则 1 会将 SVG 中的该维度应用于渲染的背景,除非被 CSS 特别覆盖。当也指定了固有比例时,该比例用于确定另一个维度。

css
div {
  background-image: url("100px-height-3x4-ratio.svg");
  background-size: 150px auto;
}

在这种情况下,我们使用 CSS 中设置的 150px 图像宽度,所以应用规则 1。然后,固有的 3:4 宽高比决定了 auto 情况下的高度。

未指定尺寸但有固有比例

如果在 SVG 中没有指定尺寸,则应用 CSS 中指定的尺寸,然后根据规则 2 使用固有比例来选择另一个维度。

css
div {
  background-image: url("no-dimensions-1x1-ratio.svg");
  background-size: 150px auto;
}

宽度由 CSS 设置为 150px。高度的 auto 值是使用该宽度和 1:1 的宽高比计算得出的,结果也是 150px

另见