用SVG绘制矩形、圆形和椭圆形。
SVG有一些预定义的形状元素,可以供开发者使用。这些元素分别是矩形、圆形 circle 、椭圆 ellipse、线条 line、多线条 polyline、多边形 polygon、路径 path 。
我们先来学习矩形的绘制。
绘制矩形使用 rect 标签,它是 rectangle 的缩写,就是矩形的意思。它是一个单标签,基本语法为:尖角号 rect,斜线尖角号。
注意,任何一个 HTML 单标签,都可以在第二个尖角号前写一个斜线,表示标签闭合了,也就是说,用闭合标签来表示单标签,其实这样写更加严谨。
它有几个重要的属性:
width,定义矩形的宽度,值是一个数字。
height,定义矩形的高度,值也是一个数字。
fill [fɪl],定义矩形的填充颜色,值可以是任意合法的颜色值,比如颜色名称,rgb颜色值,十六进制颜色值等。
stroke-width [stroʊk wɪdθ] ,笔画宽度,定义了矩形的边框宽度,值是一个数字。
stroke [stroʊk] ,描边,定义矩形边框的颜色。
我们来举个例子。
打开编辑器,创建一个 rect_circle_ellipse.html 文件,补全基础代码,在 body 里添加一个 svg 标签,定义属性 width 等于 400,height 等于 110。
在svg里添加 rect 标签,定义属性 width 等于 300,height 等于 100,fill 颜色填充值为 blue,蓝色,stroke-width 笔画宽度属性值为 3, stroke 描边属性值为 black,黑色。保存文件。
在浏览器中预览,一个矩形就绘制好了。
再来学习几个矩形的属性:
width,定义矩形的宽度,值是一个数字。
x,定义矩形的左边位置,值是一个数字。
y,定义矩形的顶部位置,值是一个数字。
fill-opacity,定义填充颜色的不透明度,合法值的范围是0 到 1。
stroke-opacity,定义描边颜色的不透明度,合法值的范围是0 到 1。
回到编辑器,在上个 svg 结尾处添加一个 br 标签。
回车换行。添加一个新的 svg 标签,属性 width 等于 400,height 等于 180。
在 svg 里面添加一个 rect 标签,属性 x 等于 50,y 等于 20,width 等于 150,height 等于 150,fill 等于 blue,stroke 等于 tomato,stroke-width 等于 5,fill-opacity 等于 0.1,stroke-opacity 等于 0.9。保存。
回到浏览器,刷新,一个边长为150,背景色为蓝色,描边为番茄色,并带有一定透明度的矩形就绘制好了。
仔细观察,背景的透明度高,边框的透明度低,它们的透明度值分别为0.1 和 0.9。这说明:透明度的值越小,透明度越高。如果值为 0,就完全透明了。
我们也可以给 rect 定义一个 opacity 属性,用来设置整个元素的不透明度值,合法值的范围也是 0 到 1。
回到编辑器,我们去掉这个矩形的 fill-opacity 和 stroke-opacity 属性,定义一个opacity 属性,值为 0.5。保存。
回到浏览器,刷新,整个矩形透明了0.5,也就是描边和背景都透明了50%。
最后,我们来绘制一个圆角矩形。
圆角矩形通过给 rect 定义 rx,ry 两个属性来实现。
rx,定义圆角x轴方向的半径长度,值是一个数字。
ry,定义圆角y轴方向的半径长度,值是一个数字。
如果两个值相等,就是一个圆形的角,两个值不相等,就是一个椭圆形的角。
回到编辑器,在上个svg结尾处添加一个 br 标签。
回车换行。添加一个新的 svg 标签,属性 width 等于 400,height 等于 180。
在 svg 里面添加一个 rect 标签,属性 x 等于 50,y 等于 20,width 等于 150,height 等于 150,fill 等于 red,stroke 等于 black,stroke-width 等于 5,opacity 等于 0.5。
最后给rect 添加 rx 等于 20,ry 等于 20。保存。
回到浏览器,刷新,一个圆角矩形做好了。
返回编辑器,如果将 ry 改为 30。保存。
回到浏览器,刷新,矩形的四个角就变成椭圆形了。
接下来,我们学习绘制圆形。
绘制圆形使用 circle 标签,circle 就是圆的意思。它是一个单标签,基本语法为:尖角号 circle,斜线尖角号。
它有三个重要的属性:
cx 和 cy 属性,定义圆心的 x 和 y 坐标。如果省略了cx和cy,圆的中心会被设置为(0,0)。
r 属性,定义圆的半径。
和绘制矩形一样,通过定义 stroke、stroke-width、fill 属性来设置边框颜色、边框宽度和背景色填充等等。
提示一下, stroke、stroke-width、fill 这三个属性,常见的图形绘制都可以使用它们。
回到编辑器,在上个svg结尾处添加一个 br 标签。回车换行。
添加一个新的 svg 标签,属性 width 等于 100,height 等于 100。
在 svg 里面添加一个 circle 标签,属性 cx 等于 50,cy 等于 50,r 等于 40,stroke 等于 black,stroke-width 等于 3,fill 等于 red。保存。
回到浏览器,刷新,一个圆形就绘制好了。
最后,我们学习绘制椭圆形。
绘制椭圆形使用 ellipse 标签,ellipse 就是椭圆的意思。它是一个单标签,基本语法为:尖角号 ellipse,斜线尖角号。
椭圆与圆密切相关。不同的是,椭圆的 x 和 y 半径是不同的,而圆的 x 和 y 半径是相等的。
ellipse 有四个重要的属性:
cx 属性,定义椭圆中心的 x 坐标。
cy 属性,定义椭圆中心的 y 坐标。
rx 属性,定义水平半径。
ry 属性,定义垂直半径。
回到编辑器,在上个svg结尾处添加一个 br 标签。回车换行。
添加一个新的 svg 标签,属性 width 等于 140,height 等于 500。
在 svg 里面添加一个 ellipse 标签,属性 cx 等于 200,cy 等于 80,rx 等于 100,ry 等于 50,fill 等于yellow,stroke 等于 purple,stroke-width 等于 2。保存。
回到浏览器,刷新,一个椭圆形就绘制好了。
返回编辑器,我们绘制三个堆叠的椭圆。在上个svg结尾处添加一个 br 标签。回车换行。
添加一个新的 svg 标签,属性 width 等于 150,height 等于 500。
在 svg 里面添加一个 ellipse 标签,属性 cx 等于 240,cy 等于 100,rx 等于 220,ry 等于 30,fill 等于purple。
再添加一个 ellipse 标签,属性 cx 等于 220,cy 等于 70,rx 等于 190,ry 等于 20,fill 等于lime。
再添加一个 ellipse 标签,属性 cx 等于 210,cy 等于 45,rx 等于 170,ry 等于 50,fill 等于yellow。保存。
回到浏览器,刷新,三个逐渐缩小的堆叠椭圆就做好了。
仔细观察发现,三个椭圆的堆叠顺序并不是html的书写顺序。这是因为他们的位置和大小是由 cx, cy, rx, ry 来决定的,不是由 html 书写顺序来决定的。根据这个特点,我们可以将多个椭圆组合起来。
返回编辑器,在上个svg结尾处添加一个 br 标签。回车换行。
添加一个新的 svg 标签,属性 width 等于 100,height 等于 500。
在 svg 里面添加一个 ellipse 标签,属性 cx 等于 240,cy 等于 50,rx 等于 220,ry 等于 30,fill 等于 yellow。
再添加一个 ellipse 标签,属性 cx 等于 220,cy 等于 50,rx 等于 190,ry 等于 20,fill 等于white。保存。
回到浏览器,刷新,视觉上看,一个空心的椭圆就绘制好了。
文章配套视频链接「链接」
明:SVG 虽然也是标签,但它不是 HTML5,标题加了 HTML5 只是为了与 canvas 放到一起。
SVG 意为可缩放矢量图形(Scalable Vector Graphics),使用 XML 格式定义矢量图形。其他的图像格式都是基于像素的,但是 SVG 没有单位的概念,它的20只是表示1的20倍,所以 SVG 绘制的图形放大或缩小都不会失真。
与其他图像比较,SVG 的优势有以下几点:
2.1、svg 标签
SVG 的代码都放到 svg 标签呢,SVG 中的标签都是闭合标签,与html中标签用法一致。svg的属性有:
eg:画一条直线,完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body style="height:600px;">
<svg width="300" height="300">
<line x1="0" y1="0" x2="100" y2="100" stroke="black" stroke-width="20"></line>
</svg>
</body>
</html>
上述 svg 设置的宽高没有带单位,此时默认是像素值,如果需要添加单位时,除了绝对单位,也可以设置相对单位。
使用语法:<svg viewBox=" x1,y1,width,height "></svg>
四个参数分别是左上角的横纵坐标、视口的宽高。表示只看SVG的某一部分,由上述四个参数决定。
使用 viewBox 之后,相当于svg整体大小不变,只能看到 viewBox 设置部分,视觉上被放大。
2.2、SVG 如何嵌入 HTML
SVG 的代码可以直接嵌入到 html 页面中,也可以通过 html 的embed、object、iframe嵌入到html中。嵌入的时候嵌入的是 SVG 文件,SVG 文件必须使用 .svg 后缀。分别介绍各种方法如何使用?
2.2.1、embed 嵌入:
使用语法:<embed src="line.svg" type="image/svg+xml"></embed>
src是SVG文件路径,type 表示 embed 引入文件类型。
优点:所有浏览器都支持,并允许使用脚本。
缺点:不推荐 html4 和 html 中使用,但 html5 支持。
2.2.2、object 嵌入:
使用语法:<object data="line.svg" type="image/svg+xml"></object>
data 是 SVG 文件路径,type 表示 object 引入文件类型。
优点:所有浏览器都支持,支持 html、html4 和 html5。
缺点:不允许使用脚本。
2.2.3、iframe 嵌入:
使用语法:<iframe width="300" height="300" src="./line.svg" frameborder="0"></iframe>
src是 SVG 文件路径,width、height、frameborder 设置的大小和边框。
优点:所有浏览器都支持,并允许使用脚本。
缺点:不推荐 html4 和 html 中使用,但 html5 支持。
2.2.4、html中嵌入:
svg 标签直接插入 html 内容内,与其他标签用法一致。
2.2.5、连接到svg文件:
使用 a 标签,直接链接到 SVG 文件。
使用语法:<a href="line.svg">查看SVG</a>
3.1、线 - line
使用语法:
<svg width="300" height="300" >
<line x1="0" y1="0" x2="300" y2="300" stroke="black" stroke-width="20"></line>
</svg>
使用line标签创建线条,(x1,y1)是起点,(x2,y2)是终点,stroke绘制黑线,stroke-width是线宽。
3.2、矩形 - rect
//使用语法:
<svg width="300" height="300" >
<rect
width="100" height="100" //大小设置
x="50" y="50" //可选 左上角位置,svg的左上角默认(0,0)
rx="20" ry="50" //可选 设置圆角
stroke-width="3" stroke="red" fill="pink" //绘制样式控制
></rect>
</svg>
上述参数 width、height是必填参数,x、y是可选参数,如不设置的时候,默认为(0,0),也就是svg的左上角开始绘制。rx、ry是可选参数,不设置是矩形没有圆角。fill定义填充颜色。
3.3、圆形 - circle
// 使用语法
<svg width="300" height="300" >
<circle
cx="100" cy="50" // 定义圆心 ,可选
r="40" // 圆的半径
stroke="black" stroke-width="2" fill="red"/> //绘制黑框填充红色
</svg>
上述(cx,xy)定义圆心的位置,是可选参数,如果不设置默认圆心是(0,0)。r是必需参数,设置圆的半径。
3.4、椭圆 - ellipse
椭圆与圆相似,不同之处在于椭圆有不同的x和y半径,而圆两个半径是相同的。
// 使用语法
<svg width="300" height="300" >
<ellipse
rx="20" ry="100" //设置椭圆的x、y方向的半径
fill="purple" // 椭圆填充色
cx="150" cy="150" //设置椭圆的圆心 ,可选参数
></ellipse>
</svg>
上述椭圆的两个rx、ry两个方向半径是必须参数,如果rx=ry就表示是圆形,(cx,cy)是椭圆的圆心,是可选参数,如果不设置,则默认圆心为(0,0)。
3.5、折线 - polyline
// 使用语法
<svg width="300" height="300" style="border:solid 1px red;">
<!-- 绘制出一个默认填充黑色的三角形 -->
<polyline
points=" //点的集合
0 ,0, // 第一个点坐标
100,100, // 第二个点坐标
100,200 // 第三个点坐标
"
stroke="green"
></polyline>
<!-- 绘制一个台阶式的一条折线 -->
<polyline
points="0,0,50,0,50,50,100,50,100,100,150,100,150,150"
stroke="#4b27ff" fill="none"
></polyline>
</svg>
上述代码执行结果如图所示:
需要注意的是 points 中包含了多个点的坐标,但不是一个数组。
3.6、多边形 - polygon
polygon 标签用来创建不少于3个边的图形,多边形是闭合的,即所有线条连接起来。
// 使用语法
<svg width="300" height="300" style="border:solid 1px red;">
<polygon
points="
0,0, //多边形的第一点
100,100, //多边形的第二点
0,100 //多边形的第三点
"
stroke="purple"
stroke-width="1"
fill="none"
></polygon>
</svg>
polygon绘制的时候与折线有些类似,但是polygon会自动闭合,折线不会。
3.7、路径 - path
path 是SVG基本形状中最强大的一个,不仅能创建其他基本形状,还能创建更多其他形状,如贝塞尔曲线、2次曲线等。
点个关注,下篇更精彩!
转品牌升级后更新了全新的Logo,今天我们用纯CSS来实现转转的新Logo,为了有一定的挑战性,这里我们只使用一个标签实现,将最大化的使用CSS能力完成Logo的绘制与动画效果。
新logo保留了原本logo里转转熊的轮廓,两个熊耳是两个卫星围绕熊头旋转,是“循环”的意思。中间倾斜的转转首字母“Z”,既像二手质检的印章,又像N——NEW的首字母,代表着全新的二手生活方式。
以上是我们要还原的Logo效果动图,现阶段使用方式主要是gif和lottie SVG两种方式。因为我们的目的是使用单标签实现所有的功能点,对于一些细节部分有所取舍,并不是百分百还原,也并不代表使用CSS的成本和效果是最好的,仅表达CSS的强大能力。接下来分析我们要核心实现的功能点:
基于上述分析接下来开始核心的代码拆解实现,在开始前先定义一些变量方便后续使用:
:root {
/* 主题色 */
--mainColor: #ff483c;
/* 字体颜色 */
--fontColor: #fff;
/* 字体宽度 */
--zWidth: 260px;
/* 中心椭圆宽高比 */
--parentScaleY: 0.9;
/* 子元素抵消比例 */
--childScaleY: calc(1 / var(--parentScaleY))
}
如果是围绕一个正圆的旋转那么实现就简单很多了,但是这里是一个椭圆,纯CSS应该怎么做呢?根据小编目前的了解大概有以下几种方式都可以实现,但是对应的效果有所区别:
对比各种情况最终使用第三个方案即可满足条件且实现成本较低,首先画出一个椭圆的边框效果,设置scaleY和border-radius将一个正方形变成椭圆形,核心代码如下:
width: 570px;
aspect-ratio: 1;
border-radius: 50%;
border: 10px solid var(--mainColor);
transform: scaleY(var(--parentScaleY));
然后给这个大圆添加旋转的动画,将整体旋转360度,这时还没有添加其他的元素,所以界面没有变化。
@keyframes circle {
0% {
transform: scaleY(var(--parentScaleY)) rotate(0);
}
100% {
transform: scaleY(var(--parentScaleY)) rotate(360deg);
}
}
设置大圆的动画执行相关参数。
animation: circle 1s 1 cubic-bezier(.5,.08,.52,.93) forwards;
边框上面的两个圈基于伪元素实现,绘制一个圆并使用定位将小圆定位于大圆的顶部两端。然后设置动画,这里需要注意的是需要设置反向旋转来抵消父级的旋转。
@keyframes mini-circle {
0%{
transform: rotate(0deg) scaleY(var(--childScaleY));
}
100%{
transform: rotate(-360deg) scaleY(var(--childScaleY));
}
}
这里为了方便查看将椭圆的参数调大进行对比,可以看到设置抵消后的区别一个圆被压缩了另一个保持了正常的圆形:
未设置抵消
已设置抵消
这里为了更好的利用元素的使用,这里将两个圆的绘制进一步优化到一个伪元素中,核心使用径向渐变背景实现,在同一个 background 中绘制两个纯色圆形,两个圆除了绘制的位置不同其他都是一样。代码如下:
background:
radial-gradient(circle 65px at 31% 24.5%,var(--mainColor) 0% 100%, transparent),
radial-gradient(circle 65px at 72% 24.5%, var(--mainColor) 0% 100%, transparent);
到此这部分的内容基本功能完成,实际效果如下:
接下来使用另一个伪元素实现 Z 字母的效果,仔细观察 Z 字母的两个拐角都是锐角效果,并不是日常字母有拐角的效果。
基于当前的样式我们可以用3段矩形拼接完成效果,上下各一段,中间一段增加旋转角度,但是只用一个伪元素如何绘制三个矩形呢,还是用到CSS渐变,这次需要用到linear-gradient线性渐变,顶部和底部正常从上往下绘制,中间的部分需要绘制线条的旋转角度,除开需要显示的颜色其他部分用#0000透明色,为了方便看效果对三个矩形更换了不同的颜色,代码如下:
background:
linear-gradient(#f00 25%, #0000 25%),
linear-gradient(#0000 75%, #29eb9a 25%),
linear-gradient(124deg, #0000 40%, #000 40% 60%, #0000 60%);
绘制的效果如下:
可以看到目前的效果还不能满足需求,两端都出现了多余的部分,需要进一步优化将其隐藏。这时候需要用到background-size与background-position,通过background-size设置绘制内容的大小,通过设置background-position设置绘制内容的起点位置,因为设置了一定的空隙部分需要增加no-repeat不重复,增加以下代码:
background-size: 80% var(--w), 80% var(--w), 100% 100%;
background-position: 0 0, 100% 0;
background-repeat: no-repeat;
此时基本符合预期的效果,但实际设计图左下角的锐角部分有超出正常矩形一部分。
所以需要对刚刚设置的size和position部分改进,将第一个矩形左侧空出16px:
background-size: 74% var(--w), 80% var(--w), 100% 100%;
background-position: 16px 0, 100% 0;
因为空出了左侧一部分距离,导致整个内容不再是一个正方形,所以需要设置 scaleX 还原宽度将图像还原到正方形。
对于刚刚设置的background相关属性可以在代码层进一步优化,使用简写将代码合并到一行:
background:
linear-gradient(var(--fontColor) 25%, #0000 25%) 16px 0 / 74% var(--zWidth) no-repeat,
linear-gradient(#0000 75%, var(--fontColor) 25%) 100% 0 / 80% var(--zWidth) no-repeat,
linear-gradient(124deg, #0000 40%, var(--fontColor) 40% 60%, #0000 60%) 0 0 / 100% 100% no-repeat;
然后继续给这个 Z 添加动画效果,默认设置 opacity: 0 隐藏,因为 Z 是小圆动画执行结束才出现的,所以还需增加动画的延迟执行时间,增加动画相关代码:
animation: z 0.3s 1s 1 ease-in-out forwards;
opacity: 0;
设置动画将内容从1.5倍缩小到正常并设置旋转角度,返抵消以及平移到Logo正中心。这里因为初始增加了1.5的放大所以设置返抵消相关参数有所不同,在设置scaleY的同时还设置了skew进一步还原尺寸。
@keyframes z {
0% {
transform: rotate(-45deg) scale(1.5) translate(0, -50%) skew(-13deg, 8deg);
opacity: 1;
}
100% {
transform: rotate(-42deg) scaleY(var(--childScaleY)) translate(-4%, -64%) skew(-13deg, 8deg);
opacity: 1;
}
}
完成后的 Z 字母动画效果:
开始动画时中心的椭圆以及2个围绕的小圆都有放大的效果,所以需要对前面动画关键帧的定义继续完善。
小圆部分执行动画的前10%也增加scale(0.5)。
@keyframes mini-circle {
0%{
transform: rotate(0) scale(0.5);
}
10%{
transform: rotate(0) scaleY(var(--childScaleY));
}
}
大圆执行动画的前10%部分增加scale(0.8)。大圆部分还有一个效果是字母 Z 出现的时候中心的椭圆由边框圆变成实心圆,所以是在动画结束前增加对背景色的变化,代码如下:
@keyframes circle {
0% {
transform: scale(0.8) rotate(0);
}
10% {
transform: scaleY(var(--parentScaleY)) rotate(0);
}
80% {
background-color: var(--fontColor);
}
100% {
background-color: var(--mainColor);
transform: scaleY(var(--parentScaleY)) rotate(360deg);
}
}
到此我们整个代码实现过程就结束了,基于一个标签实现了转转的Logo的绘制及动画效果。当然这只是对其主要的功能还原,如需完整还原细节还需要进一步优化。
CSS的确是足够强大且对很多复杂的图形效果都能实现,这里我们主要是使用渐变背景实现图案的绘制,除了渐变还可以使用CSS阴影也能达到类似的效果。使用CSS对比使用SVG或GIF在资源体积上有很大的提升,本次实现的Logo使用lottie的json需要100KB左右,使用GIF大约需要27KB左右,但是纯CSS实现仅1KB不到即可完成,但是对于较为复杂的场景对应的代码也提升了不少的复杂度,大家要根据实际的情况使用,感兴趣的同学欢迎留言交流。
作者:大转转FE
来源:微信公众号:大转转FE
出处:https://mp.weixin.qq.com/s/CUfAKou5LEYtwzYB83LWdA
*请认真填写需求信息,我们会在24小时内与您取得联系。