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 SVG
the gradient drawing in .
More SVG
articles in the series: SVG basics , SVG animation , Transform in SVG .
Overview
Maybe you have css
experience 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 SVG
drawing, 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>
复制代码
For the setting of gradient color, we can't css
write 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>
复制代码
Usually, we define the gradient label <linearGradient>
in the <defs>
element, and <linearGradient>
its id
attribute 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-color
attributes define the position and color value of the color stop respectively, and it also has an attribute stop-opacity
that sets stop-color
the 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>
复制代码
The 30% area on the left of the rectangle is filled with a #DCE35B
solid color, and the 30% area on the right is filled with a #45B649
solid color. The real gradient only appears in the middle 40% of the rectangle.
如果两个颜色都设为50%,就得到了两块均分矩形的实色。在这基础上,我们可以生成各种颜色的条纹图案。
渐变的方向和范围
在没有设置渐变方向的时候,渐变的默认方向是从左向右。
如果要设定渐变方向,要用到<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)
。
x1="0" y1="0" x2="0" y2="1"
表示从(0,0)
到(0,1)
,即渐变方向从矩形上边框垂直向下到下边框。
x1="0" y1="0.3" x2="0" y2="0.7"
的情形如下: 可以看出,x1
,y1
,x2
,y2
不仅决定渐变的方向,还决定了渐变的范围,超出渐变范围的部分由起始或结束色标的颜色进行纯色填充。
案例1:渐变文字
<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>
复制代码
文字的填充,我们用了垂直方向的渐变色,对于每一行文字,都是从黄色渐变到绿色。
如果要将这几行文字作为一个整体来设置渐变色,像下面这样,应该怎样设置呢?
这就要用到gradientUnits
属性了。
gradientUnits
属性定义渐变元素(<linearGradient>
、<radialGradient>
)要参考的坐标系。 它有两个取值:objectBoundingBox
和 userSpaceOnUse
。
默认值是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。
}
复制代码
gradientUnits:userSpaceOnUse
适用于画布中有多个图形,但每个图形都是整体渐变中的一部分这样的场景。值得注意的是,当gradientUnits="userSpaceOnUse"
时,x1
,y1
,x2
,y2
的取值只有用%
百分数这样的相对单位才表示比例,如果取值为x2="1"
,那就真的是1px
,这一点与gradientUnits="objectBoundingBox"
是不同的。
案例2:渐变的环形进度条
在上一篇文章中,我们实现了可交互的环形进度条: 这里我们将其改造成渐变的环形进度条。
使用渐变色作为描边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>
复制代码
径向渐变
基础使用
径向渐变是色彩从中心点向四周辐射的渐变。
<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元素。
cx
和cy
定义径向渐变范围的圆心,(50%, 50%)
意味着是引用该渐变的SVG元素的中心。r
设定渐变范围的半径,当r=50%
时,说明渐变范围的半径在x
和y
方向的分别是引用该渐变的SVG元素width
和height
的50%。
//当rect高度减小时,渐变在y方向的半径也减小。
<rect fill="url(#test)" x="10" y="10" width="150" height="100"></rect>
复制代码
在cx,cy,r
都取默认值的情况下,径向渐变的范围刚好覆盖引用该渐变的SVG元素。实际开发中,我们常常需要调整渐变范围。
渐变起点的移动
在默认情况下,渐变起点都是在渐变范围的中心,如果想要不那么对称的渐变,就需要改变渐变起点的位置。
<radialGradient>
的fx
和fy
就是用来设置渐变色起始位置的。fx
和fy
的值也是相对值,相对的也是引用该渐变的SVG元素。
我们可以设定渐变的范围(cx
,cy
,r
),也可以设定渐变的起点位置(fx
,fy
)。但是如果渐变的起点位置在渐变的范围之外,会出现一些我们不想要的效果。
测试代码如下,可直接运行:
<!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>
复制代码
综合案例:透明的泡泡
最后我们用线性渐变和径向渐变画一个泡泡。
分析:
- 背景是一个用线性渐变填充的矩形。
- 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-color
the value rgba
, or we can stop-opacity
set stop-color
the 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/