踏足SVG 深入浅出全方位介绍SVG的功能及特性 - 基础篇(五)

768 阅读4分钟

前言

上一篇文章中主要介绍了 SVG 的一些容器元素以及一些实际的。以及一些实际的应用场景。这一篇文章,将会介绍 SVG 内的渐变以及 clipPath 剪切的操作。

往期文章

踏足SVG | 深入浅出全方位介绍SVG的功能及特性 - 基础篇(一)

踏足SVG | 深入浅出全方位介绍SVG的功能及特性 - 基础篇(二)

踏足SVG | 深入浅出全方位介绍SVG的功能及特性 - 基础篇(三)

踏足SVG | 深入浅出全方位介绍SVG的功能及特性 - 基础篇(四)

SVG 渐变

线性渐变沿着直线改变颜色,要插入一个线性渐变,你需要在SVG文件的defs元素内部,创建一个<linearGradient> 节点。

linearGradient 线性渐变

渐变 linearGradient 需要再 <defs> 内进行声明。通过 <stop> 来分割渐变的区域

可用在 fill 或 stroke 中使用渐变

属性:

  • x1 开始点的 x 坐标
  • y1 开始点的 y 坐标
  • x2 结束点的 x 坐标
  • y2 结束点的 y 坐标
  • spreadMethod 到达终点后的渐变行为
    • pad 中止 (默认)
    • reflect 重复来回(0% -> 100% -> 0%)
    • repeat 重复(0% -> 100% jumpTo 0% -> 100%)
  • gradientUnits 渐变容器应用不同的坐标系
    • objectBoundingBox(默认) 以被渐变元素作为坐标系
    • userSpaceOnUse 以 SVG 画布作为坐标系
  • gradientTransform 渐变变形(后面单独说明)

通过 x1,y1 和 x2,y2 来确定渐变的方向和渐变范围

设置 gradientUnits:userSpaceOnUse。位置坐标设置 0 - 1就不是百分比了,而是当前所在 SVG 容器的坐标值

简单使用

例1:在 fill 和 stroke 中使用

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <linearGradient id="Gradient1" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stop-color="red"/>
        <stop offset="100%" stop-color="blue" stop-opacity="0.2"/>
      </linearGradient>
    </defs>
    <rect x="10" y="10" width="100" height="100" fill="url(#Gradient1)"></rect>
  </svg>
  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <linearGradient id="Gradient1" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stop-color="#FF0000"/>
        <stop offset="100%" stop-color="#0000FF" stop-opacity="0.2"/>
      </linearGradient>
    </defs>
    <rect x="10" y="10" width="100" height="100" stroke="url(#Gradient1)" stroke-width="10" fill="none"></rect>
  </svg>

LinearGradient_1.png

stop-color 可以使用 rgba 格式

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <linearGradient id="Gradient2" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stop-color="rgba(255,0,0,.6)"/>
        <stop offset="100%" stop-color="rgba(0,0,255,.2)"/>
      </linearGradient>
    </defs>
    <rect x="10" y="10" width="100" height="100" fill="url(#Gradient2)"></rect>
  </svg>

LinearGradient_2.png

应用不同的坐标系 userSpaceOnUse & objectBoundingBox

同patternContentUnits

  <svg class="border" width="250" height="250" viewBox="0 0 250 250">
    <defs>
      <linearGradient id="Gradient_objectBoundingBox" x1="0" y1="0" x2="0" y2="1" gradientUnits="objectBoundingBox">
        <stop offset="0%" stop-color="red"/>
        <stop offset="100%" stop-color="blue" stop-opacity="0.2"/>
      </linearGradient>
    </defs>
    <defs>
      <linearGradient id="Gradient_userSpaceOnUse" x1="130" y1="10" x2="130" y2="110" gradientUnits="userSpaceOnUse">
        <stop offset="0%" stop-color="red"/>
        <stop offset="100%" stop-color="blue" stop-opacity="0.2"/>
      </linearGradient>
    </defs>
    <rect x="10" y="10" width="100" height="100" fill="url(#Gradient_objectBoundingBox)"></rect>
    <rect x="130" y="10" width="100" height="100" fill="url(#Gradient_userSpaceOnUse)"></rect>
  </svg>

LinearGradient_3.png

spreadMethod 到达终点后的渐变行为

在 objectBoundingBox 坐标系下更为明显。下面的示例将使用 userSpaceOnUse 坐标系

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <!-- 重复来回 -->
      <linearGradient id="Gradient3" x1="0" y1="0" x2="0" y2="80" spreadMethod="reflect" gradientUnits="userSpaceOnUse">
        <stop offset="0%" stop-color="rgba(255,0,0,1)"/>
        <stop offset="100%" stop-color="rgba(0,0,255,.2)"/>
      </linearGradient>
    </defs>
    <rect x="10" y="10" width="80" height="80" fill="url(#Gradient3)"></rect>
    <rect x="100" y="10" width="80" height="180" fill="url(#Gradient3)"></rect>
  </svg>
  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <!-- 重复 -->
      <linearGradient id="Gradient4" x1="0" y1="0" x2="0" y2="80" spreadMethod="repeat" gradientUnits="userSpaceOnUse">
        <stop offset="0%" stop-color="rgba(255,0,0,1)"/>
        <stop offset="100%" stop-color="rgba(0,0,255,.2)"/>
      </linearGradient>
    </defs>
    <rect x="10" y="10" width="80" height="80" fill="url(#Gradient4)"></rect>
    <rect x="100" y="10" width="80" height="180" fill="url(#Gradient4)"></rect>
  </svg>
  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <!-- 中止,以最终目标颜色继续填充 -->
      <linearGradient id="Gradient5" x1="0" y1="0" x2="0" y2="80" spreadMethod="pad" gradientUnits="userSpaceOnUse">
        <stop offset="0%" stop-color="rgba(255,0,0,1)"/>
        <stop offset="100%" stop-color="rgba(0,0,255,.2)"/>
      </linearGradient>
    </defs>
    <rect x="10" y="10" width="80" height="80" fill="url(#Gradient5)"></rect>
    <rect x="100" y="10" width="80" height="180" fill="url(#Gradient5)"></rect>
  </svg>

LinearGradient_4.png

radialGradient 径向渐变

径向渐变与线性渐变相似,只是它是从一个点开始发散绘制渐变。创建径向渐变需要在文档的defs中添加一个<radialGradient>元素

可用在 fill 或 stroke 中使用渐变

属性:

  • cx 中心点 x 坐标
  • cy 中心点 y 坐标
  • r 圆的半径
  • fx 焦点的 x 坐标
  • fy 焦点的 y 坐标
  • fr 焦点的 半径。焦点的颜色继承渐变最初的颜色
  • spreadMethod 到达终点后的渐变行为
    • pad 中止 (默认)
    • reflect 重复来回(0% -> 100% -> 0%)
    • repeat 重复(0% -> 100% jumpTo 0% -> 100%)
  • gradientUnits 渐变容器应用不同的坐标系
    • objectBoundingBox(默认) 以被渐变元素作为坐标系
    • userSpaceOnUse 以 SVG 画布作为坐标系
  • gradientTransform 渐变变形(后面单独说明)

简单使用

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <radialGradient id="Gradient1" cx="0.5" cy="0.5" r="0.5">
        <stop offset="0%" stop-color="red"/>
        <stop offset="100%" stop-color="blue"/>
      </radialGradient>
    </defs>
    <rect x="10" y="10" width="100" height="100" fill="url(#Gradient1)"></rect>
  </svg>

radialGradient_1.png

定义焦点

在默认情况下焦点为园的中点。

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <!-- 不设置焦点默认焦点位置在中心点 -->
      <radialGradient id="Gradient2" cx="0.5" cy="0.5" r="0.5" >
        <stop offset="0%" stop-color="red"/>
        <stop offset="100%" stop-color="blue"/>
      </radialGradient>
      <radialGradient id="Gradient3" 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" width="80" height="80" fill="url(#Gradient2)"></rect>
    <rect x="10" y="100" width="80" height="80" fill="url(#Gradient3)"></rect>
  </svg>

radialGradient_2.png

不同的坐标系及 spreadMethod

linearGradient 相同。效果如下

userSpaceOnUse

<svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <radialGradient id="Gradient7" cx="100" cy="100" r="80" gradientUnits="userSpaceOnUse">
        <stop offset="0%" stop-color="red"/>
        <stop offset="100%" stop-color="blue"/>
      </radialGradient>
    </defs>
    <rect x="10" y="10" width="80" height="80" fill="url(#Gradient7)"></rect>
  </svg>

radialGradient_4.png

spreadMethod

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <radialGradient id="Gradient4" cx="0.5" cy="0.5" r="0.2" spreadMethod="pad">
        <stop offset="0%" stop-color="red"/>
        <stop offset="100%" stop-color="blue"/>
      </radialGradient>
    </defs>
    <rect x="10" y="10" width="80" height="80" fill="url(#Gradient4)"></rect>
  </svg>
  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <radialGradient id="Gradient5" cx="0.5" cy="0.5" r="0.2" spreadMethod="repeat">
        <stop offset="0%" stop-color="red"/>
        <stop offset="100%" stop-color="blue"/>
      </radialGradient>
    </defs>
    <rect x="10" y="10" width="80" height="80" fill="url(#Gradient5)"></rect>
  </svg>
  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <radialGradient id="Gradient6" cx="0.5" cy="0.5" r="0.2" spreadMethod="reflect">
        <stop offset="0%" stop-color="red"/>
        <stop offset="100%" stop-color="blue"/>
      </radialGradient>
    </defs>
    <rect x="10" y="10" width="80" height="80" fill="url(#Gradient6)"></rect>
  </svg>

radialGradient_3.png

clipPath 剪切

定义一条剪切路径,可作为其他元素的 clip-path 属性的值。 剪切路径限制了图形的可见范围。从概念上来说,如果图形超出了当前剪切路径所包围的区域,那么超出部分将不会绘制。

clipPath 定义的路径,在定义路径里的会被展示,外侧的则被剪切

属性:

  • clipPathUnits 裁剪容器应用不同的坐标系(同patternContentUnits
    • objectBoundingBox(默认) 以被裁剪元素作为坐标系
    • userSpaceOnUse 以 SVG 画布作为坐标系

简单使用

在一个矩形中裁剪出一个圆

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
    <defs>
      <clipPath id="cut">
        <!-- 裁剪元素的颜色不会对裁剪有效果 -->
        <circle cx="100" cy="100" r="50" fill="red">
      </clipPath>
    </defs>
    <rect x="0" y="0" width="200" height="200" fill="green" clip-path="url(#cut)"/>
  </svg>

clipPath_1.png

通过 clipPath 实现填充动画

两个图形:爱心图形的描边和被爱心图形裁剪背景色矩形

实现原理:设置固定位置的裁剪图形,通过动态改变背景矩形的位置来实现填充的效果

  <svg class="border" width="200" height="200" viewBox="0 0 200 200">
   <defs>
     <clipPath id="cut3">
       <path id="heart" transform="scale(0.2)" d="M667.786667 117.333333C832.864 117.333333 938.666667 249.706667 938.666667 427.861333c0 138.250667-125.098667 290.506667-371.573334 461.589334a96.768 96.768 0 0 1-110.186666 0C210.432 718.368 85.333333 566.112 85.333333 427.861333 85.333333 249.706667 191.136 117.333333 356.213333 117.333333c59.616 0 100.053333 20.832 155.786667 68.096C567.744 138.176 608.170667 117.333333 667.786667 117.333333z"></path>
     </clipPath>
   </defs>
   <rect id="rect" x="0" y="180" width="200" height="160" fill="#E91E63" clip-path="url(#cut3)"/>
   <use href="#heart" fill="transparent" stroke="#E91E63" stroke-width="20"></use>
 </svg>
 <div class="input">
   <div>输入 0 - 100</div>
   <input type="text" onchange="setLikeValue(event)">
 </div>
   function setLikeValue(e){
     const value = e.target.value;
     const reg = /^[0-9]+$/;
     if(!reg.test(value) || +value > 100) return
     // 初始 y - 高度所占高
     anime({
       targets: '#rect',
       y:180 - (+value/100) * 160
     });
   }

pathClip.gif

效果和mask制作的填充基本一致。mask实现填充

比较 clipPath 与 mask

  1. clipPath 是对定义区域将路径内的内容进行裁剪
  2. mask 是对定义内的内容通过自身透度合成新的内容
  3. clipPath 不能通过 fill stroke opacity 控制展示内容,只进行路径裁剪。mask 是合成,可以通过 fill stroke opacity 控制展示内容
  4. clipPath 能实现的 mask 都能实现。且还可以控制最后展示的内容。在一定程度上 mask 是更高级版的 clipPath

最后

至此,SVG 的基础篇已经结束,下面我会继续为大家带来 SVG 滤镜及动画使用方法的详细介绍。喜欢的朋友可以关注一下。

参考资料

参考来源 - MDN