注册

如何美化你的图表,关于SVG渐变你需要了解的一切!

渐变在网页设计中几乎随处可见,渐变的背景、文字、按钮、图表等等,相比于纯色,渐变的颜色显得更加灵动自然。

今天我们要探讨的,就是SVG中的渐变绘制。

更多SVG系列文章:SVG基础知识、SVG动画、SVG中的Transform变换。

概述

或许你有使用css绘制渐变图形的经验,如果要绘制一个渐变的矩形,我们可以这样写:

<div></div>

.bg{
  height: 100px;
  width: 200px;
  //给元素设置渐变背景
  background: linear-gradient(#fb3,#58a);
}

使用SVG绘图,颜色是通过设置元素的fill(填充颜色)和stroke(边框颜色)属性来实现。

<rect height="100" width="150" stroke="#45B649" stroke-width="2" fill="#DCE35B"></rect>

de40f84f30264ca0a1357970442b5db5~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

对于渐变颜色的设置,我们不能像在css中那样,直接写fill="linear-gradient(color1, color2)",而要使用专门的渐变标签:<linearGradient>(线性渐变) 和 <radialGradient>(径向渐变)。

线性渐变

基础使用

先来看一个最简单的例子,如何绘制一个线性渐变的矩形:

<svg>
  <defs>
      <linearGradient id="gradient-test">
          <stop offset="0%" stop-color="#DCE35B" />
          <stop offset="100%" stop-color="#45B649" />
      </linearGradient>
  </defs>
  <rect height="100" width="150" fill="url(#gradient-test)"></rect>
</svg>

71d70080b97e441daccc278d6d901889~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

通常,我们将渐变标签<linearGradient>定义在<defs>元素中,<linearGradient>id属性作为其唯一标识,方便后面需要使用的地方对其进行引用。

<linearGradient>中的<stop>标签定义渐变色的色标,它的offsetstop-color属性分别定义色标的位置和颜色值,它还有一个属性stop-opacity,设定stop-color颜色的透明度。

如果将色标的位置拉近:

<linearGradient id="gradient-1">
  <stop offset="30%" stop-color="#DCE35B" />
  <stop offset="70%" stop-color="#45B649" />
</linearGradient>

3fd1155002e84340b0072836a2dd6269~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

矩形左边的 30% 区域被填充为 #DCE35B 实色,而右边 30% 区域被填充为 #45B649 实色。真正的渐变只出现在矩形中间 40% 的区域。

如果两个颜色都设为50%,就得到了两块均分矩形的实色。在这基础上,我们可以生成各种颜色的条纹图案。

e6e8ccbdbb7c42c1888d8d8dd590c79d~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

渐变的方向和范围

在没有设置渐变方向的时候,渐变的默认方向是从左向右。

如果要设定渐变方向,要用到<linearGradient>x1,y1,x2,y2这几个属性。

<linearGradient id="gradient-1" x1="0" y1="0" x2="0" y2="1">
  <stop offset="0%" stop-color="#DCE35B" />
  <stop offset="100%" stop-color="#45B649" />
</linearGradient>

我们知道,在平面上,方向一般由向量来表示。而渐变的方向由(x1,y1)(起点)和(x2,y2)(点)两个点定义的向量来表示。

在一般的应用场景中,x1,y1,x2,y2的取值范围是[0,1](或者用百分数[0%, 100%])。

对于矩形而言,不管矩形的长宽比例是多少,它的左上角对应的都是(0,0),右下角则对应(1,1)

4b1b4a26dd284b70b281ffd26c67205d~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

x1="0" y1="0" x2="0" y2="1"表示从(0,0)(0,1),即渐变方向从矩形上边框垂直向下到下边框。

x1="0" y1="0.3" x2="0" y2="0.7"的情形如下:

e26576168bd64097bf803c7e9377db5f~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

可以看出,x1,y1,x2,y2不仅决定渐变的方向,还决定了渐变的范围,超出渐变范围的部分由起始或结束色标的颜色进行纯色填充。

案例1:渐变文字

55a6d213ec554ef69142fe5f37cb3ecf~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

<svg width="600" height="270">
  <defs>
      <linearGradient id="background">                         <!--背景渐变色-->
          <stop offset="0%" stop-color="#232526" />
          <stop offset="100%" stop-color="#414345" />
      </linearGradient>
      <linearGradient id="text-color" x1="0" y1="0" x2="0" y2="100%"> <!--文字渐变色-->
          <stop offset="0%" stop-color="#DCE35B" />
          <stop offset="100%" stop-color="#45B649" />
      </linearGradient>
  </defs>
  <rect x="0" y="0" height="100%" width="100%" fill="url(#background)"></rect>
  <text y="28%" x="28%">试问闲情都几许?</text>
  <text y="44%" x="28%">一川烟草</text>
  <text y="60%" x="28%">满城风絮</text>
  <text y="76%" x="28%">梅子黄时雨</text>
</svg>
<style>
  text{
      font-size: 32px;
      letter-spacing:5px;
      fill:url(#text-color);     //文字的填充使用渐变色
  }
</style>

文字的填充,我们用了垂直方向的渐变色,对于每一行文字,都是从黄色渐变到绿色。

如果要将这几行文字作为一个整体来设置渐变色,像下面这样,应该怎样设置呢?

aab0f39f921a4f90b4787f7494d4203f~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

这就要用到gradientUnits属性了。

gradientUnits属性定义渐变元素(<linearGradient><radialGradient>)要参考的坐标系。 它有两个取值:objectBoundingBoxuserSpaceOnUse

默认值是objectBoundingBox,它定义渐变元素的参考坐标系为引用该渐变的SVG元素,渐变的起止、范围、方向都是基于引用该渐变的SVG元素(之前的<rect>,这里的<text>)自身,比如这里的每一个<text>元素的左上角都是渐变色的(0,0)位置,右下角都是(100%,100%)

userSpaceOnUse则以当前的SVG元素视窗区域(viewport) 为渐变元素的参考坐标系。也就是SVG元素的左上角为渐变色的(0,0)位置,右下角为(100%,100%)

<svg height="200" width="300"> 
  <defs>
      <!-- 定义两个渐变,除了gradientUnits,其他配置完全相同 -->
      <linearGradient id="gradient-1" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="objectBoundingBox">
          <stop offset="0%" stop-color="#C6FFDD" />
          <stop offset="100%" stop-color="#f7797d" />
      </linearGradient>
      <linearGradient id="gradient-2" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="userSpaceOnUse">
          <stop offset="0%" stop-color="#C6FFDD" />
          <stop offset="100%" stop-color="#f7797d" />
      </linearGradient>
  </defs>
  <rect x="0" y="0" ></rect>
  <rect x="150" y="0" ></rect>
  <rect x="0" y="100" ></rect>
  <rect x="150" y="100" ></rect>
</svg>
rect{
  height: 100px;
  width: 150px;
  fill: url(#gradient-1); //四个矩形都填充渐变色,下面左图为gradient-1,右图为gradient-2。
}

4169e762f9a34677b09f587c8176e21b~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

gradientUnits:userSpaceOnUse 适用于画布中有多个图形,但每个图形都是整体渐变中的一部分这样的场景。值得注意的是,当gradientUnits="userSpaceOnUse"时,x1,y1,x2,y2的取值只有用%百分数这样的相对单位才表示比例,如果取值为x2="1",那就真的是1px,这一点与gradientUnits="objectBoundingBox"是不同的。

案例2:渐变的环形进度条

上一篇文章中,我们实现了可交互的环形进度条:

ca39729ac08f4c72a505dc304261e911~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

这里我们将其改造成渐变的环形进度条。

e18fe4fce7a447e29284a0f0d315dadc~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

使用渐变色作为描边stroke的颜色,中间使用一个白色透明度渐变的圆,增加立体感。

<!--改动部分的代码-->
<svg height="240" width="240" viewBox="0 0 100 100">
  <defs>
      <linearGradient id="circle">
          <stop offset="0%" stop-color="#A5FECB" />
          <stop offset="50%" stop-color="#20BDFF" />
          <stop offset="100%" stop-color="#5433FF" />
      </linearGradient>
      <linearGradient id="center">
          <stop offset="0%" stop-color="rgba(255,255,255,0.25)" />
          <stop offset="100%" stop-color="rgba(255,255,255,0.08)" />
        </linearGradient>
    </defs>
    <!--灰色的背景圆环-->
    <circle cx="50" cy="50" r="40" stroke-width="12" stroke="#eee" fill="none"></circle>
    <!--渐变的动态圆环-->
    <circle      
       
        cx="50" cy="50" r="40"
        transform="rotate(-90 50 50)"
        stroke-width="12"
        stroke="url(#circle)"
        fill="none"
        stroke-linecap="round"
        stroke-dasharray="251"></circle>
    <!--白色透明度渐变的圆,增加立体感-->
    <circle cx="50" cy="50" r="40" fill="url(#center)"></circle>
</svg>

径向渐变

基础使用

径向渐变是色彩从中心点向四周辐射的渐变。

a5f3947e04bd48dc9baa54204a8160dd~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

<svg height="300" width="200">
<defs>
<radialGradient id="test">
<stop offset="0%" stop-color="#e1eec3" />
<stop offset="100%" stop-color="#f05053" />
</radialGradient>
</defs>
<rect fill="url(#test)" x="10" y="10" width="150" height="150"></rect>
</svg>

和线性渐变的结构类似,我们将径向渐变标签<radialGradient>定义在<defs>元素中,其id属性作为其唯一标识,以便后面需要使用的地方对其进行引用。

<radialGradient>中的<stop>标签定义渐变色的色标,它的offsetstop-color属性分别定义色标的位置和颜色值。

渐变的范围

径向渐变的范围由<radialGradient>cx,cy,r三个属性共同决定,它们的默认值均是50%,是相对值,相对的是引用该渐变的SVG元素

cxcy定义径向渐变范围的圆心,(50%, 50%)意味着是引用该渐变的SVG元素的中心。r设定渐变范围的半径,当r=50%时,说明渐变范围的半径在xy方向的分别是引用该渐变的SVG元素widthheight的50%。

//当rect高度减小时,渐变在y方向的半径也减小。
<rect fill="url(#test)" x="10" y="10" width="150" height="100"></rect>

ad55d6e8734e40cebe14f53fb808dc87~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

cx,cy,r都取默认值的情况下,径向渐变的范围刚好覆盖引用该渐变的SVG元素。实际开发中,我们常常需要调整渐变范围。

e4c7c3b11dd840288bc860dee6a02972~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

渐变起点的移动

在默认情况下,渐变起点都是在渐变范围的中心,如果想要不那么对称的渐变,就需要改变渐变起点的位置。

<radialGradient>fxfy就是用来设置渐变色起始位置的。fxfy的值也是相对值,相对的也是引用该渐变的SVG元素

b682316c4ca942b7bacf44de6d28e61e~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

我们可以设定渐变的范围(cx,cy,r),也可以设定渐变的起点位置(fx,fy)。但是如果渐变的起点位置在渐变的范围之外,会出现一些我们不想要的效果。

8bed4914f25745709146c7493d939d3f~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

测试代码如下,可直接运行:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
      body{
          display: flex;
          justify-content: center;
      }
      .control{
          margin-top:20px;
      }
  </style>
</head>
<body>
  <svg height="300" width="200">
      <defs>
          <radialGradient id="test">
              <stop offset="0%" stop-color="#e1eec3" />
              <stop offset="100%" stop-color="#f05053" />
          </radialGradient>
      </defs>
      <rect fill="url(#test)" x="10" y="10" width="150" height="150"></rect>
  </svg>
  <div>
      <div>cx:<input value="50" type="range" min="0" max="100" id="cx" /></div>
      <div>cy:<input value="50" type="range" min="0" max="100" id="cy" /></div>
      <div>r:<input value="50" type="range" min="0" max="100" id="r" /></div>
      <div>fx:<input value="50" type="range" min="0" max="100" id="fx" /></div>
      <div>fy:<input value="50" type="range" min="0" max="100" id="fy" /></div>
  </div>
  <script>
      const rg = document.getElementById('test')
      document.querySelectorAll('input').forEach((elem) => {
          elem.addEventListener('change', (ev) => {
              rg.setAttribute(ev.target.id, ev.target.value+'%')
          })
      })
  </script>
</body>
</html>

综合案例:透明的泡泡

最后我们用线性渐变和径向渐变画一个泡泡。

c83c197fcb8b4291a1d0cf8f95810276~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

分析:

  • 背景是一个用线性渐变填充的矩形。

  • 泡泡分为三个部分:由径向渐变填充的一个圆形和两个椭圆。

这里的径向渐变主要是颜色透明度的渐变。设定颜色透明度,我们可以直接指定stop-color的值为rgba,也可以通过stop-opacity来设定stop-color颜色的透明度。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
      .bubble{
          animation: move 5s linear infinite;
          animation-direction:alternate;
      }
      //泡泡的运动
      @keyframes move {
          0%{
              transform: translate(0,0);
          }
          50%{
              transform: translate(250px,220px);
          }
          100%{
              transform: translate(520px,50px);
          }
      }
  </style>
</head>
<body>
  <svg height="400" width="700">
      <defs>
          <!--背景的线性渐变-->
          <linearGradient id="background">
              <stop offset="0%" stop-color="#DCE35B" />
              <stop offset="100%" stop-color="#45B649" />
          </linearGradient>
          <!--光斑的径向渐变,通过fx、fy设置不对称的渐变-->
          <radialGradient id="spot" fx="50%" fy="30%">
              <stop offset="10%" stop-color="white" stop-opacity=".7"></stop>  
              <stop offset="70%" stop-color="white" stop-opacity="0"></stop>
          </radialGradient>
          <!--泡泡本体的径向渐变-->
          <radialGradient id="bubble">
              <stop offset="0%" stop-color="rgba(255,255,255,0)" ></stop>  
              <stop offset="80%" stop-color="rgba(255,255,255,0.1)" ></stop>
              <stop offset="100%" stop-color="rgba(255,255,255,0.42)"></stop>
          </radialGradient>
      </defs>
      <rect fill="url(#background)" width="100%" height="100%"></rect>
      <g>
          <circle cx="100" cy="100" r="70" fill="url(#bubble)"></circle>
          <ellipse rx="50" ry="20" cx="80" cy="60" fill="url(#spot)" transform="rotate(-25, 80, 60)" ></ellipse>
          <ellipse rx="20" ry="10" cx="140" cy="130" fill="url(#spot)" transform="rotate(125, 140, 130)" ></ellipse>
      </g>  
  </svg>
</body>
</html>

以上渐变配色均来自网站: uigradients.com/

作者:Alaso
来源:juejin.cn/post/7098637240825282591

0 个评论

要回复文章请先登录注册