今天有群小伙伴问我如何用CSS实现如下Loading效果:这是个很有意思的问题。我们知道,使用CSS,我们可以轻松实现这样的动画效果:
div{width:100px;height:100px;border-radius:50%;border:2pxsolidtransparent;border-top:2pxsolid#000;border-left:2pxsolid#000;animation:rotate3sinfinitelinear;}@keyframesrotate{100%{transform:rotate(360deg);}}动画如下:对比需要的行加载动画,上面的动画是missing核心点是在旋转运动的过程中,线的长度会发生变化。所以,这里的难点就换成了如何动态实现弧线段长度的变化呢?解决这个问题,基本上就是解决了上面说的线变换加载动画。本文将介绍CSS中几个有趣的可能动态改变弧线长度的方法:方法一:使用蒙版实现第一种方法,也是比较容易想到的,使用蒙版来实现。我们实现两条半圆线,一条是实际可以看到的颜色,一条和背景颜色一样,比较粗的一条半圆线。当两条线的速度不一致时,我们可以直观地看到,还可以看到动态变化的弧线。看示意图,一眼就明白了:我们把上面的红线换成白底,整体的动画效果很相似。伪代码如下:
div{width:200px;height:200px;}div::before{position:absolute;content:"";top:0px;left:0px;right:0px;bottom:0px;border-radius:50%;border:3pxsolidtransparent;border-top:3pxsolid#000;border-left:3pxsolid#000;animation:rotate3sinfiniteease-out;}div::after{position:absolute;content:"";上:-2px;左:-2px;右:-2px;下:-2px;border-radius:50%;border:7pxsolidtransparent;border-bottom:7pxsolid#fff;border-right:7pxsolid#fff;animation:rotate4sinfiniteease-in-out;}@keyframesrotate{100%{transform:rotate(0deg);}}核心是实现两条半圆线,一条黑色,一条背景色,两条线移动速度不同(由动画时间和慢动作控制)。效果如下:完整代码可以猛戳--CodePenDemo-LinearLoading[1]上面方案最大的两个问题是:如果背景色不是纯色,会暴露。如果要求能显示的线段长度大于半个圆,则无法完成。基于此,我们只能另辟蹊径。方法二:借助SVG的stroke-*能力在之前的很多文章中,我们都提到了借助CSS和SVG,我们可以实现各种简单或复杂的线条动画,比如简单的:或者自定义复杂路径的复杂线条动画:>如果你对用CSS/SVG实现线条动画感兴趣,但又不是很了解,可以看我的文章——【Web动画】SVG线条动画入门[2],这里,我们只需要一个简单的SVG使用其CSS样式stroke-dasharray和stroke-dashoffset标签轻松实现上述效果:
.circular{width:100px;height:100px;animation:rotate2slinearinfinite;}.path{stroke-dasharray:1,200;stroke-dashoffset:0;stroke:#000;animation:dash1.5sease-in-outinfinite}@keyframesrotate{100%{transform:rotate(360deg);}}@keyframesdash{0%{stroke-dasharray:1,200;stroke-dashoffset:0;}50%{stroke-dasharray:89,200;stroke-dashoffset:-35px;}100%{stroke-dasharray:89,200;stroke-dashoffset:-124px;}}简要说明:stroke:类比css中的border-color,为svg图形设置边框颜色;stroke-dasharray:值为一组数组,没有上限,每个数字交替代表划线和区间的宽度;stroke-dashoffset:路径的破折号模式起始距离我们用stroke-dasharray把原来完整的线切割成多段,假设stroke-dasharray:10,10代表这样一个图:第一个10代表线段的长度,第二个10代表两条可见的线分割两者之间的差距。实际代码中的stroke-dasharray:1,200表示两条1px的线段之间间隔200px。由于直径为40px的圆的周长为40*π≈125.6px,小于200,实际图如下图。只有一点:同理,stroke-dasharray:89,200的意思是:通过动画,让线段在这两种状态之间进行tween。stroke-dashoffset的作用是将线段往前推,配合父容器的transform:rotate()旋转动画,这样视觉效果就是线段一直在一个方向旋转。结果如下:完整代码可以点这里:CodePenDemo--Linearloading[3]OK,有同学会说,我不想引入SVG标签,我只想用纯CSS方案。在这里,还有一个使用CSS@property的纯CSS解决方案。使用CSS@property进行二次曲线渐变移动。这里我们需要利用CSS的@property的能力来移动无法动画的角度渐变。这个方法,我在介绍CSS@property的文章中也提到过——CSS@property,makingtheimpossiblepossible[4]通常情况下,渐变是不能动画的,如下图:.normal{width:200px;高度:200px;边框半径:50%;背景:圆锥渐变(黄绿,黄绿25%,透明25%,透明100%);过渡:背景300毫秒;&:悬停{背景:圆锥渐变(黄绿,黄绿60%,透明60.1%,transparent100%);}}会得到这样的效果,因为conic-gradient不支持过渡动画,得到的是直接从一帧到另一帧的变化:嗯,用CSS@property自定义变量变换:@property--per{syntax:'';inherits:false;initial-value:25%;}div{background:conic-gradient(yellowgreen,yellowgreenvar(--per),transparentvar(--per),transparent100%);transition:--per300mslinear;&:hover{--per:60%;}}看看变换后的效果:这里,我们可以让渐变动态的移动,赋予anima的能力特。我们只需要再次引入遮罩,将中间部分剪掉,就可以实现上面一行的加载动画。伪代码如下:@property--per{syntax:"";inherits:false;initial-value:10%;}div{position:relative;width:100px;高度:100px;边框半径:50%;动画:旋转11sinfiniteease-in-out;&::before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;border-radius:50%;background:conic-gradient(transparent,transparentvar(--per),#fa7var(--per),#fa7);mask:radial-gradient(transparent,transparent47.5px,#00048px,#000);动画:change3sinfinitecubic-bezier(0.57,0.29,0.49,0.76);}}@keyframeschange{50%{transform:rotate(270deg);--per:98%;}100%{transform:rotate(720deg);}}@keyframesrotate{100%{transform:rotate(360deg);filter:hue-rotate(360deg);}}这里我顺便加上了filter:hue-rotate(),这样线条旋转时颜色会发生变化。最终效果如下。这是一个纯CSS的方案:完整代码可以点这里:LinearLoadingAnimation[5]唯一的问题是目前对CSS@property的兼容性不太乐观。当然,未来是光明的。最后简单总结一下。本文介绍3种实现动态弧线长度变化的Loading动画。当然,它们各有优缺点。实际使用时,根据实际情况选择。有时,裁剪图片也可能是一种节省时间的方式。好了,本文到此结束,希望本文对大家有所帮助:)有什么问题或者建议可以多交流,原创文章,文笔有限,人才辈出,如有不妥之处,敬请谅解,请告诉我。参考资料[1]CodePenDemo-LinearLoading:https://codepen.io/Chokcoco/pen/PvqYNJ[2][WebAnimation]SVGLineAnimation介绍:https://www.cnblogs.com/coco1s/p/6225973.html[3]CodePenDemo--线性加载:https://codepen.io/Chokcoco/pen/jOGQGJP?editors=1100[4]CSS@property,让不可能成为可能:https://github.com/chokcoco/iCSS/issues/109[5]线性加载动画:https://codepen.io/Chokcoco/pen/ZEXmJxP?editors=1100[6]Github--iCSS:https://github.com/chokcoco/iCSS