How to beautify your diagrams, everything you need to know about SVG gradients!

Gradients can be seen almost everywhere in web design. Gradient backgrounds, text, buttons, charts, etc., are more flexible and natural than solid colors.

What we are going to discuss today is SVGthe gradient drawing in .

More SVGarticles in the series: SVG basics , SVG animation , Transform in SVG .

Overview

Maybe you have cssexperience in drawing gradient graphics. If you want to draw a gradient rectangle, we can write:

<div class="bg"></div>

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

With SVGdrawing, color is achieved by setting the element's fill(fill color) and stroke(border color) properties.

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

image.pngFor the setting of gradient color, we can't csswrite it directly like in fill="linear-gradient(color1, color2)", but use special gradient tags: <linearGradient>(linear gradient) and <radialGradient>(radial gradient).

Linear Gradient

Basic use

Let's first look at the simplest example, how to draw a linear gradient rectangle:

<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>
复制代码

image.pngUsually, we define the gradient label <linearGradient>in the <defs>element, and <linearGradient>its idattribute is used as its unique identifier, which is convenient to refer to it in the place where it needs to be used later.

<linearGradient>The <stop>tag in defines the color stop of the gradient color, and its offset and  stop-colorattributes define the position and color value of the color stop respectively, and it also has an attribute stop-opacitythat sets stop-colorthe transparency of the color.

If you move the color stops closer:

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

image.pngThe 30% area on the left of the rectangle is filled with a #DCE35Bsolid color, and the 30% area on the right is filled with a #45B649solid color. The real gradient only appears in the middle 40% of the rectangle.

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

image.png

渐变的方向和范围

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

如果要设定渐变方向,要用到<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)

image.png

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

x1="0" y1="0.3" x2="0" y2="0.7"的情形如下: image.png 可以看出,x1,y1,x2,y2不仅决定渐变的方向,还决定了渐变的范围,超出渐变范围的部分由起始或结束色标的颜色进行纯色填充。

案例1:渐变文字

image.png

<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>
复制代码

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

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

image.png

这就要用到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。
}
复制代码

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

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

上一篇文章中,我们实现了可交互的环形进度条: image.png 这里我们将其改造成渐变的环形进度条。

progress-circle.gif 使用渐变色作为描边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       
         class="process-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> 
复制代码

径向渐变

基础使用

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

image.png

<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>标签定义渐变色的色标,它的offset 和 stop-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>
复制代码

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

progress-ctrl-cxyr.gif

渐变起点的移动

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

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

progress-ctrl-fxyr.gif

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

image.png

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

<!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 class="control">
        <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>
复制代码

综合案例:透明的泡泡

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

bubble.gif

分析:

  • 背景是一个用线性渐变填充的矩形。
  • The bubble is divided into three parts: a circle and two ellipses filled with radial gradients.

The radial gradient here is mainly a gradient of color transparency. To set the color transparency, we can directly specify stop-colorthe value rgba, or we can stop-opacityset stop-colorthe transparency of the color through.

<!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 class="bubble">
            <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>
复制代码

The above gradient colors are all from the website: uigradients.com/

Guess you like

Origin juejin.im/post/7098637240825282591