SVG 中的渐变

除了简单的填充和描边之外,更令人兴奋的或许是,您还可以创建和应用渐变作为填充或描边。

SVG 渐变有两种类型:线性渐变和径向渐变。它们与使用它们的位置分开定义,这有助于重用。您必须为每个渐变指定一个 id 属性,以允许其他元素引用它。渐变定义可以放在 <defs> 元素或 <svg> 元素中。

线性渐变

线性渐变沿直线变化。要插入一个线性渐变,您需要在 SVG 文件的 <defs> 部分内创建一个 <linearGradient> 节点。

基本示例

html
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="Gradient1">
      <stop class="stop1" offset="0%" />
      <stop class="stop2" offset="50%" />
      <stop class="stop3" offset="100%" />
    </linearGradient>
    <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
      <stop offset="0%" stop-color="red" />
      <stop offset="50%" stop-color="black" stop-opacity="0" />
      <stop offset="100%" stop-color="blue" />
    </linearGradient>
  </defs>
  <style>
    #rect1 {
      fill: url("#Gradient1");
    }
    .stop1 {
      stop-color: red;
    }
    .stop2 {
      stop-color: black;
      stop-opacity: 0;
    }
    .stop3 {
      stop-color: blue;
    }
  </style>

  <rect id="rect1" x="10" y="10" rx="15" ry="15" width="100" height="100" />
  <rect
    x="10"
    y="120"
    rx="15"
    ry="15"
    width="100"
    height="100"
    fill="url(#Gradient2)" />
</svg>

上面是一个将线性渐变应用于 <rect> 元素的示例。线性渐变内部有多个 <stop> 节点。这些节点通过指定位置的 offset 属性和 stop-color 属性来告诉渐变在特定位置应该是什么颜色。这可以直接分配,也可以通过 CSS 分配。出于本示例的目的,这两种方法已混合使用。例如,这个例子告诉渐变从红色开始,中间变为透明黑色,最后变为蓝色。您可以插入任意数量的停止颜色,以创建您需要的漂亮或丑陋的混合,但偏移量应始终从 0%(或如果您想省略百分号,则为 0)增加到 100%(或 1)。重复的值将使用在 XML 树中分配最远的停止点。此外,与填充和描边一样,您可以指定 stop-opacity 属性来设置该位置的不透明度(同样,在 FF3 中,您也可以使用 rgba 值来完成此操作)。

svg
<stop offset="100%" stop-color="yellow" stop-opacity="0.5"/>

要使用渐变,您必须从对象的 fillstroke 属性中引用它。这与您在 CSS 中引用元素的方式相同,使用 url。在这种情况下,url 只是对我们渐变的引用,该渐变具有创意 ID“Gradient1”。要附加它,将 fill 设置为 url("#Gradient1"),瞧!我们的对象现在是多色的。您可以对 stroke 执行相同的操作。

svg
<style>
  #rect1 {
    fill: url("#Gradient1");
  }
</style>

<linearGradient> 元素还接受其他几个属性,这些属性指定渐变的大小和外观。渐变的方向由两个点控制,由属性 x1x2y1y2 指定。这些属性定义了渐变所沿的线。渐变默认为水平方向,但可以通过更改这些属性来旋转它。上面示例中的 Gradient2 旨在创建垂直渐变。

html
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1"></linearGradient>

注意:您也可以在渐变上使用 href 属性。使用此属性时,一个渐变的属性和停止点可以包含在另一个渐变中。在上面的示例中,您不必在 Gradient2 中重新创建所有停止点。

html
<linearGradient id="Gradient1">
  <stop id="stop1" offset="0%" />
  <stop id="stop2" offset="50%" />
  <stop id="stop3" offset="100%" />
</linearGradient>
<linearGradient
  id="Gradient2"
  x1="0"
  x2="0"
  y1="0"
  y2="1"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  href="#Gradient1" />

我们在这里直接在节点上包含了 xlink 命名空间,尽管通常您会在文档顶部定义它。当我们谈论图像时,会对此有更多介绍。

径向渐变

径向渐变与线性渐变相似,但它们绘制的渐变从一个点向外辐射。要创建径向渐变,您需要在文档的 <defs> 部分添加一个 <radialGradient> 元素。

基本示例

html
<?xml version="1.0" standalone="no"?>
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <radialGradient id="RadialGradient1">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
    <radialGradient id="RadialGradient2" cx="0.25" cy="0.25" r="0.25">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
  </defs>

  <rect
    x="10"
    y="10"
    rx="15"
    ry="15"
    width="100"
    height="100"
    fill="url(#RadialGradient1)" />
  <rect
    x="10"
    y="120"
    rx="15"
    ry="15"
    width="100"
    height="100"
    fill="url(#RadialGradient2)" />
</svg>

这里使用的停止点与之前相同,但现在对象中心将是红色,并向各个方向逐渐变为蓝色。与线性渐变一样,<radialGradient> 节点可以接受多个属性来描述其位置和方向。然而,与线性渐变不同,它要复杂得多。径向渐变再次由两个点定义,这两个点决定了它的边缘。第一个点定义了一个渐变结束的圆。它需要一个中心点,由 cxcy 属性指定,以及一个半径 r。设置这三个属性将允许您移动渐变并更改其大小,如上面第二个 rect 所示。

第二个点称为焦点,由 fxfy 属性定义。第一个点描述了渐变的边缘,而焦点描述了它的中间位置。通过示例更容易理解这一点。

中心点和焦点

html
<?xml version="1.0" standalone="no"?>

<svg width="120" height="120" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <radialGradient id="Gradient" cx="0.5" cy="0.5" r="0.5" fx="0.25" fy="0.25">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
  </defs>

  <rect
    x="10"
    y="10"
    rx="15"
    ry="15"
    width="100"
    height="100"
    fill="url(#Gradient)"
    stroke="black"
    stroke-width="2" />

  <circle
    cx="60"
    cy="60"
    r="50"
    fill="transparent"
    stroke="white"
    stroke-width="2" />
  <circle cx="35" cy="35" r="2" fill="white" stroke="white" />
  <circle cx="60" cy="60" r="2" fill="white" stroke="white" />
  <text x="38" y="40" fill="white" font-family="sans-serif" font-size="10pt">
    (fx,fy)
  </text>
  <text x="63" y="63" fill="white" font-family="sans-serif" font-size="10pt">
    (cx,cy)
  </text>
</svg>

如果焦点移到前面描述的圆圈之外,渐变将无法正确渲染,因此该点将被假定为在圆圈边缘之内。如果没有给出焦点,则假定它与中心点在同一位置。

线性和径向渐变还接受其他几个属性来描述它们可能经历的变换。我在这里想提及的唯一其他属性是 spreadMethod 属性。此属性控制当渐变到达其终点但对象尚未填充时会发生什么。它可以采用三个值之一:"pad""reflect""repeat""pad" 是您到目前为止所看到的。当渐变到达其终点时,最终偏移颜色用于填充对象的其余部分。"reflect" 导致渐变继续,但反向反射,从 100% 处的颜色偏移开始,然后返回到 0% 处的偏移,然后再返回。"repeat" 也允许渐变继续,但不是向后,而是直接跳回开头并再次运行。

扩展方法

html
<?xml version="1.0" standalone="no"?>

<svg width="220" height="220" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <radialGradient
      id="GradientPad"
      cx="0.5"
      cy="0.5"
      r="0.4"
      fx="0.75"
      fy="0.75"
      spreadMethod="pad">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
    <radialGradient
      id="GradientRepeat"
      cx="0.5"
      cy="0.5"
      r="0.4"
      fx="0.75"
      fy="0.75"
      spreadMethod="repeat">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
    <radialGradient
      id="GradientReflect"
      cx="0.5"
      cy="0.5"
      r="0.4"
      fx="0.75"
      fy="0.75"
      spreadMethod="reflect">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </radialGradient>
  </defs>

  <rect
    x="10"
    y="10"
    rx="15"
    ry="15"
    width="100"
    height="100"
    fill="url(#GradientPad)" />
  <rect
    x="10"
    y="120"
    rx="15"
    ry="15"
    width="100"
    height="100"
    fill="url(#GradientRepeat)" />
  <rect
    x="120"
    y="120"
    rx="15"
    ry="15"
    width="100"
    height="100"
    fill="url(#GradientReflect)" />

  <text x="15" y="30" fill="white" font-family="sans-serif" font-size="12pt">
    Pad
  </text>
  <text x="15" y="140" fill="white" font-family="sans-serif" font-size="12pt">
    Repeat
  </text>
  <text x="125" y="140" fill="white" font-family="sans-serif" font-size="12pt">
    Reflect
  </text>
</svg>

两种渐变还有一个名为 gradientUnits 的属性,它描述了您在描述渐变大小或方向时将使用的单位系统。这里有两种可能的值:"userSpaceOnUse""objectBoundingBox""objectBoundingBox" 是默认值,所以这就是到目前为止所展示的。它实质上将渐变缩放到对象的大小,因此您只需指定从零到一的值的坐标,它们就会自动缩放到对象的大小。userSpaceOnUse 本质上接受绝对单位。所以您必须知道对象的位置,并将渐变放置在相同的位置。上面的径向渐变将被重写

html
<radialGradient
  id="Gradient"
  cx="60"
  cy="60"
  r="50"
  fx="35"
  fy="35"
  gradientUnits="userSpaceOnUse"></radialGradient>

您还可以通过使用 gradientTransform 属性将另一个变换应用于渐变,但由于我们尚未介绍变换,我们将把它留到以后再讨论。

当对象边界框不是正方形时,处理 gradientUnits="objectBoundingBox" 还有一些其他注意事项,但它们相当复杂,需要更了解情况的人来解释。