学习制作一个加载动画——loading.svg

2,126 阅读3分钟

这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战 image.png

前文

今天突然心血来潮要做个loading动画,用css做总感觉哪里不对劲,于是决定用svg来做好了。 问题是没用过svg做加载动画,只好先看看教程了

先看今天的成果

1.gif

首先了解一下svg怎么用

先去看看MDN文档,浏览一下标签和属性的大概作用,然后拿里面的demo玩玩先。

  1. 用img标签引用 <img src="loading.svg" />

  2. 用css的background-image background-image: url(loading.svg);

  3. 用object、iframe、embed标签

<object data="loading.svg" type="image/svg+xml"></object>
<iframe src="loading.svg" frameborder="0"></iframe>
<embed src="loading.svg" type="" />

常见标签有这些

  1. text:文本元素
  2. line:直线元素
  3. rect:矩形元素
  4. circle:圆形元素
  5. ellipse:椭圆元素
  6. path:路径元素
  7. polyline:折线元素
  8. polygon:多边形元素
  9. g:元素组合/集合

常见属性有这些

  1. x:x轴坐标
  2. y:y轴坐标
  3. width:宽
  4. height:高
  5. rx:矩形圆角(椭圆)的x轴的半径
  6. ry:矩形圆角(椭圆)的y轴的半径
  7. r:圆的半径
  8. cx:圆(椭圆)中心点的x轴坐标
  9. cy:圆(椭圆)中心点的y轴坐标
  10. points:坐标点集合,逗号隔开
  11. d:点集数列以及其它关于如何绘制路径的信息
  12. stroke:画笔属性(描边用的)
  13. stroke-width:画笔大小
  14. fill:填充的颜色

举个栗子

image.png

// 文字
<text x="15" y="300" fill="blue" font-family="sans-serif" font-size="16pt">Text</text>
// 矩形
<rect x="10" y="10" width="30" height="30"></rect>
// 圆角矩形
<rect x="60" y="10" rx="10" ry="10" width="30" height="30"></rect>
// 圆形
<circle cx="140" cy="30" r="20"></circle>
// 椭圆
<ellipse cx="200" cy="30" rx="20" ry="5"></ellipse>
// 直线
<line stroke="#f44" x1="10" x2="50" y1="60" y2="90"></line>
// 折线
<polyline points="60 110, 65 120, 70 115, 75 130, 80 125, 85 140, 90 135, 95 150, 100 145" />
// 多边形
<polygon points="50 160, 55 180, 70 180, 60 190, 65 205, 50 195, 35 205, 40 190, 30 180, 45 180" />
// 路径 (路劲太复杂,我这个渣渣没学会,我是用AI画的)
<path d="M357.2,141v-24.2c0-3.1-2.5-5.6-5.6-5.6h-66.1c-3.1,0-5.6,2.5-5.6,5.6V141c0,3.1-2.5,5.6-5.6,5.6H129.7 c-3.1,0-5.6,2.5-5.6,5.6v43.1v8.1v30.9c0,3.1,2.5,5.6,5.6,5.6H167c3.1,0,5.6-2.5,5.6-5.6v-42.6c0-3.1,2.5-5.6,5.6-5.6h283.6 c3.1,0,5.6,2.5,5.6,5.6v42.6c0,3.1,2.5,5.6,5.6,5.6h31.7c3.1,0,5.6-2.5,5.6-5.6v-33.9v-8.1v-40.1c0-3.1-2.5-5.6-5.6-5.6H362.8 C359.7,146.5,357.2,144,357.2,141z"/>

我自己学到的路径是这个亚子的

<path>元素是SVG基本形状中最强大的一个,可以用它创建线条, 曲线, 弧形等等。 path元素的形状是通过属性d定义的,属性d的值是一个“命令+参数”的序列

  • M = moveto:移动画笔但不画,有坐标点两个参数(M x y)
  • L = lineto:画一条直线,从当前位置到参数的坐标点(L x y)
  • H = horizontal lineto:水平直线(H x)
  • V = vertical lineto:垂直直线(V x)
  • C = curveto:三次贝塞尔曲线,有三个坐标点作为参数(C x1 y1, x2 y2, x y)
  • S = smooth curveto:可以创建多个和前面一样的贝塞尔曲线,从而创建连续的曲线,跟在C或S后面的话,它的第一个控制点将作为前一个曲线的第二个控制点的中心对称点
  • Q = quadratic Belzier curve:二次贝塞尔曲线,有两个坐标点作为参数
  • T = smooth quadratic Belzier curveto:可以创建多个二次贝塞尔曲线,从而创建连续的曲线
  • A = elliptical Arc:弧线,和椭圆一样的参数
  • Z = closepath:结束符号

在svg中使用css

前面说到的demo都是黑色的,是因为没上色,现在就用strokefill来上色

image.png 直线是没有填充的,所以fill是无效的,其他的用 stroke="red" fill="#4ff" 上色就好了 问题来了,这么多个上色那么麻烦,统一的办法有没有 答案是有的,用defs标签定义css样式,用法和html一毛一样

<defs>
    <style type="text/css"><![CDATA[
       .color {
         stroke: red;
         fill: #4ff;
       }
    ]]></style>
</defs>

但是那么多个元素,一个个加样式也是麻烦,于是用g标签把所有的元素包含起来,加上样式就舒服多了

<g class="color">
    <rect x="10" y="10" width="30" height="30"></rect>
    ......
</g>

其中有一个想样式不一样行吗?直接用style内联就可以了。

<text x="15" y="300" style="fill:blue" font-family="sans-serif" font-size="16pt">Text</text>

svg的渐变

这些都需要放到defs标签里面

  1. linearGradient:线性渐变 stop标签能够指定颜色,由offset控制偏移,stop-color控制颜色,stop-opacity控制透明度
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
      // 水平渐变
      <linearGradient id="Gradient1">
        <stop class="stop1" offset="0%"/>
        <stop class="stop2" offset="50%"/>
        <stop class="stop3" offset="100%"/>
      </linearGradient>
      // 垂直渐变(想要什么方向,就自己修改两个坐标的指向)
      <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
        <stop offset="0%" stop-color="red"/>
        <stop offset="50%" stop-color="black" stop-opacity="0"/>
        <stop offset="100%" stop-color="blue"/>
      </linearGradient>
      <style type="text/css"><![CDATA[
        #rect1 { fill: url(#Gradient1); }
        .stop1 { stop-color: red; }
        .stop2 { stop-color: black; stop-opacity: 0; }
        .stop3 { stop-color: blue; }
      ]]></style>
  </defs>

  <rect id="rect1" x="10" y="10" rx="15" ry="15" width="100" height="100"/>
  <rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#Gradient2)"/>

</svg>
  1. radialGradient:径向渐变 使用方式和线性渐变几乎一样,多了个中心焦点
  • fx和fy是焦点参数
  • cx,cy和r是中心的参数
<?xml version="1.0" standalone="no"?>

<svg width="120" height="120" version="1.1"
  xmlns="http://www.w3.org/2000/svg">
  <defs>
      <radialGradient id="Gradient"
            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" rx="15" ry="15" width="100" height="100"
        fill="url(#Gradient)" stroke="black" stroke-width="2"/>

  <circle cx="60" cy="60" r="50" fill="transparent" stroke="white" stroke-width="2"/>
  <circle cx="35" cy="35" r="2" fill="white" stroke="white"/>
  <circle cx="60" cy="60" r="2" fill="white" stroke="white"/>
  <text x="38" y="40" fill="white" font-family="sans-serif" font-size="10pt">(fx,fy)</text>
  <text x="63" y="63" fill="white" font-family="sans-serif" font-size="10pt">(cx,cy)</text>

</svg>

我要把我的加载动画拿出来了

image.png 如果有哪里写得不好,记得告诉我,让我们一起进步吧

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 640 640" style="enable-background:new 0 0 640 640;" xml:space="preserve">
    <defs>
        <linearGradient id="left-to-right">
            <stop offset="0" stop-color="#e02e42">
                <animate dur="1.5s" attributeName="offset" from="0" to="1.5" repeatCount="indefinite" />
            </stop>
            <stop offset="0" stop-color="#eee">
                <animate dur="1.5s" attributeName="offset" from="0" to="1.5" repeatCount="indefinite" />
            </stop>
        </linearGradient>
    </defs>
    <g fill="url(#left-to-right)" stroke-width="10">
        <path d="M357.2,141v-24.2c0-3.1-2.5-5.6-5.6-5.6h-66.1c-3.1,0-5.6,2.5-5.6,5.6V141c0,3.1-2.5,5.6-5.6,5.6H129.7
			c-3.1,0-5.6,2.5-5.6,5.6v43.1v8.1v30.9c0,3.1,2.5,5.6,5.6,5.6H167c3.1,0,5.6-2.5,5.6-5.6v-42.6c0-3.1,2.5-5.6,5.6-5.6h283.6
			c3.1,0,5.6,2.5,5.6,5.6v42.6c0,3.1,2.5,5.6,5.6,5.6h31.7c3.1,0,5.6-2.5,5.6-5.6v-33.9v-8.1v-40.1c0-3.1-2.5-5.6-5.6-5.6H362.8
			C359.7,146.5,357.2,144,357.2,141z"/>
        <path d="M317.3,378.8L178,426c-9,3-15,11.4-15,20.9v64.8c0,12.2,9.9,22.1,22.1,22.1h274.6c12.2,0,22.1-9.9,22.1-22.1
			v-65c0-9.4-5.9-17.8-14.8-20.9l-135.3-47.1C327,377.2,322,377.2,317.3,378.8z M401.6,493.2H246.2c-12.2,0-22.1-9.9-22.1-22.1V471
			c0-9.6,6.2-18.1,15.4-21l76.3-24.2c4.3-1.4,8.9-1.4,13.2-0.1l79.1,24.4c9.3,2.9,15.6,11.4,15.6,21.1l0,0
			C423.7,483.3,413.8,493.2,401.6,493.2z"/>
        <path d="M512.4,368l-120-43.5c-4.7-1.7-4.6-8.3,0.1-9.9l26.5-8.8l27.4-9.9c2.1-0.8,3.5-2.7,3.5-4.9v-38.6v-4.2V222
			c0-2.9-2.3-5.2-5.2-5.2H241.4V206c0-1.8-1.4-3.2-3.2-3.2h-43c-1.8,0-3.2,1.4-3.2,3.2v70.8c0,1.8,1.4,3.2,3.2,3.2h43
			c1.8,0,3.2-1.4,3.2-3.2v-20.6c0.3-2.7,2.5-4.7,5.2-4.7h150.8c2.9,0,5.2,2.3,5.2,5.2v13.1c0,2.2-1.4,4.2-3.5,4.9l-71.2,25.1
			c-1.2,0.4-2.5,0.4-3.7-0.1l-44.9-18.1c-3.4-1.4-7.2,1.2-7.2,4.9v29.1c0,2.2-1.4,4.2-3.5,5L130.5,368c-2.1,0.7-3.5,2.7-3.5,5v36.7
			c0,3.6,3.6,6.2,7,4.9L321.2,347c1.1-0.4,2.3-0.4,3.5,0L508.9,409c3.4,1.1,6.9-1.4,6.9-5v-31.1C515.9,370.7,514.5,368.7,512.4,368z"/>
    </g>
    <style>@keyframes r{0%{stroke-dasharray:15.5,3100;stroke-dashoffset:0;transform:rotate(0);}50%{stroke-dasharray:1395,2325;stroke-dashoffset:-620}100%{stroke-dasharray:1395,2325;stroke-dashoffset:-1860;transform:rotate(1turn)}}.rotate{transform-origin:50% 50%;animation:r 1.5s ease-in-out infinite;stroke:currentColor;stroke-width:20;stroke-linecap:round;color:#e02e42}</style>
    <circle class="rotate" cx="320" cy="320" r="310" fill="none"></circle>
</svg>

效果