【第1816期】巧用 CSS 实现酷炫的充电动画

作者:chokcoco

关注前言

看着这些就觉得很美妙。今日早读文章由腾讯@chokcoco授权分享。

正文从这开始~~

循序渐进,看看只使用 CSS ,可以鼓捣出什么样的充电动画效果。

画个电池

当然,电池充电,首先得用 CSS 画一个电池,这个不难,随便整一个:

欧了,勉强就是它了。有了电池,那接下来直接充电吧。最最简单的动画,那应该是用色彩把整个电池灌满即可。

方法很多,代码也很简单,直接看效果:

有内味了,如果要求不高,这个勉强也就能够交差了。通过蓝色渐变表示电量,通过色块的位移动画实现充电的动画。但是总感觉少了点什么。

增加阴影及颜色的变化

如果要继续优化的话,需要添加点细节。

我们知道,低电量时,电量通常表示为红色,高电量时表示为绿色。再给整个色块添加点阴影的变化,呼吸的感觉,让充电的效果看起来确实是在动。

知识点

到这里,其实只有一个知识点:

使用 filter: hue-rotate() 对渐变色彩进行色彩过渡变换动画

我们无法对一个渐变色直接进行 animation ,这里通过滤镜对色相进行调整,从而实现了渐变色的变换动画。

完整Demo:https://codepen.io/Chokcoco/pen/bGNqyra?editors=1100

  1. <div class="container">

  2. <div class="battery"></div>

  3. </div>

  1. html,

  2. body {

  3. width: 100%;

  4. height: 100%;

  5. display: flex;

  6. background: #e4e4e4;

  7. }


  8. .container {

  9. position: relative;

  10. width: 140px;

  11. margin: auto;

  12. }


  13. .battery {

  14. height: 220px;

  15. box-sizing: border-box;

  16. border-radius: 15px 15px 5px 5px;

  17. filter: drop-shadow(0 1px 3px rgba(0,0,0,0.22));

  18. background: #fff;

  19. z-index: 1;


  20. &::before {

  21. content: "";

  22. position: absolute;

  23. width: 26px;

  24. height: 10px;

  25. left: 50%;

  26. top: 0;

  27. transform: translate(-50%, -10px);

  28. border-radius: 5px 5px 0 0;

  29. background: rgba(240, 240, 240, .88);

  30. }


  31. &::after {

  32. content: "";

  33. position: absolute;

  34. left: 0;

  35. right: 0;

  36. bottom: 0;

  37. top: 90%;

  38. background: linear-gradient(to bottom, #7abcff 0%, #00BCD4 44%, #2196F3 100%);

  39. border-radius: 0px 0px 5px 5px;

  40. box-shadow: 0 14px 28px rgba(33, 150, 243, 0), 0 10px 10px rgba(9, 188, 215, 0.08);

  41. animation: charging 6s linear infinite;

  42. filter: hue-rotate(90deg);

  43. }

  44. }


  45. @keyframes charging {

  46. 50% {

  47. box-shadow: 0 14px 28px rgba(0, 150, 136, 0.83), 0px 4px 10px rgba(9, 188, 215, 0.4);

  48. }


  49. 95% {

  50. top: 5%;

  51. filter: hue-rotate(0deg);

  52. border-radius: 0 0 5px 5px;

  53. box-shadow: 0 14px 28px rgba(4, 188, 213, .2), 0 10px 10px rgba(9, 188, 215, 0.08);

  54. }

  55. 100% {

  56. top: 0%;

  57. filter: hue-rotate(0deg);

  58. border-radius: 15px 15px 5px 5px;

  59. box-shadow: 0 14px 28px rgba(4, 188, 213, 0), 0 10px 10px rgba(9, 188, 215, 0.4);

  60. }

  61. }

添加波浪

ok,刚刚算一个小里程碑,接下来再进一步。电量的顶部为一条直线有点呆呆的感觉,这里我们进行改造一下,如果能将顶部直线,改为波浪滚动,效果会更为逼真一点。

改造之后的效果:

使用 CSS 实现这种波浪滚动效果,其实只是用了一种障眼法,具体的可以我早期写的这篇文章:纯 CSS 实现波浪效果!

知识点

这里的一个知识点就是上述说的使用 CSS 实现简易的波浪效果,通过障眼法实现,看看图就明白了:

完整Demo:https://codepen.io/Chokcoco/pen/qBErGoO

  1. <div class="container">

  2. <div class="header"></div>

  3. <div class="battery">

  4. </div>

  5. <div class="battery-copy">

  6. <div class="g-wave"></div>

  7. <div class="g-wave"></div>

  8. <div class="g-wave"></div>

  9. </div>

  10. </div>

  1. html,

  2. body {

  3. width: 100%;

  4. height: 100%;

  5. display: flex;

  6. background: #e4e4e4;

  7. }


  8. .container {

  9. position: relative;

  10. width: 140px;

  11. margin: auto;

  12. }


  13. .header {

  14. position: absolute;

  15. width: 26px;

  16. height: 10px;

  17. left: 50%;

  18. top: 0;

  19. transform: translate(-50%, -10px);

  20. border-radius: 5px 5px 0 0;

  21. background: rgba(255, 255, 255, .88);

  22. }


  23. .battery-copy {

  24. position: absolute;

  25. top: 0;

  26. left: 0;

  27. height: 220px;

  28. width: 140px;

  29. border-radius: 15px 15px 5px 5px;

  30. overflow: hidden;

  31. }


  32. .battery {

  33. position: relative;

  34. height: 220px;

  35. box-sizing: border-box;

  36. border-radius: 15px 15px 5px 5px;

  37. box-shadow: 0 0 5px 2px rgba(255, 255, 255, 0.22);

  38. background: #fff;

  39. z-index: 1;


  40. &::after {

  41. content: "";

  42. position: absolute;

  43. left: 0;

  44. right: 0;

  45. bottom: 0;

  46. top: 80%;

  47. background: linear-gradient(to bottom, #7abcff 0%, #00BCD4 44%, #2196F3 100%);

  48. border-radius: 0px 0px 5px 5px;

  49. box-shadow: 0 14px 28px rgba(33, 150, 243, 0), 0 10px 10px rgba(9, 188, 215, 0.08);

  50. animation: charging 10s linear infinite;

  51. filter: hue-rotate(90deg);

  52. }

  53. }


  54. .g-wave {

  55. position: absolute;

  56. width: 300px;

  57. height: 300px;

  58. background: rgba(255, 255, 255, .8);

  59. border-radius: 45% 47% 44% 42%;

  60. bottom: 25px;

  61. left: 50%;

  62. transform: translate(-50%, 0);

  63. z-index: 1;

  64. animation: move 10s linear infinite;

  65. }


  66. .g-wave:nth-child(2) {

  67. border-radius: 38% 46% 43% 47%;

  68. transform: translate(-50%, 0) rotate(-135deg);

  69. }


  70. .g-wave:nth-child(3) {

  71. border-radius: 42% 46% 37% 40%;

  72. transform: translate(-50%, 0) rotate(135deg);

  73. }


  74. @keyframes charging {

  75. 50% {

  76. box-shadow: 0 14px 28px rgba(0, 150, 136, 0.83), 0px 4px 10px rgba(9, 188, 215, 0.4);

  77. }


  78. 95% {

  79. top: 5%;

  80. filter: hue-rotate(0deg);

  81. border-radius: 0 0 5px 5px;

  82. box-shadow: 0 14px 28px rgba(4, 188, 213, .2), 0 10px 10px rgba(9, 188, 215, 0.08);

  83. }

  84. 100% {

  85. top: 0%;

  86. filter: hue-rotate(0deg);

  87. border-radius: 15px 15px 5px 5px;

  88. box-shadow: 0 14px 28px rgba(4, 188, 213, 0), 0 10px 10px rgba(9, 188, 215, 0.4);

  89. }

  90. }


  91. @keyframes move {

  92. 100% {

  93. transform: translate(-50%, -160px) rotate(720deg);

  94. }

  95. }

OK,到这,上述效果加上数字变化已经算是一个比较不错的效果了。当然上面的效果看上去还是很 CSS 的,就是一眼看到就觉得用 CSS 是可以做到的。

使用强大的 CSS 滤镜实现安卓充电动画效果

那下面这个呢?

用安卓手机的同学肯定不陌生,这个是安卓手机在充电的时候的效果。看到这个我就很好奇,使用 CSS 能做到吗?

经过一番尝试,发现使用 CSS 也是可以很好的模拟这种动画效果:

上述 Gif 录制的效果图是完全使用 CSS 模拟的效果。

完整Demo:https://codepen.io/Chokcoco/pen/vYExwvm

  1. <div class="g-container">

  2. <div class="g-number">98.7%</div>

  3. <div class="g-contrast">

  4. <div class="g-circle"></div>

  5. <ul class="g-bubbles">

  6. <li></li>

  7. <li></li>

  8. <li></li>

  9. <li></li>

  10. <li></li>

  11. <li></li>

  12. <li></li>

  13. <li></li>

  14. <li></li>

  15. <li></li>

  16. <li></li>

  17. <li></li>

  18. <li></li>

  19. <li></li>

  20. <li></li>

  21. </ul>

  22. </div>

  23. </div>

  1. html,

  2. body {

  3. width: 100%;

  4. height: 100%;

  5. display: flex;

  6. background: #000;

  7. overflow: hidden;

  8. }


  9. .g-number {

  10. position: absolute;

  11. width: 300px;

  12. top: 27%;

  13. text-align: center;

  14. font-size: 32px;

  15. z-index: 10;

  16. color: #fff;

  17. }


  18. .g-container {

  19. position: relative;

  20. width: 300px;

  21. height: 400px;

  22. margin: auto;

  23. }


  24. .g-contrast {

  25. filter: contrast(15) hue-rotate(0);

  26. width: 300px;

  27. height: 400px;

  28. background-color: #000;

  29. overflow: hidden;

  30. animation: hueRotate 10s infinite linear;

  31. }


  32. .g-circle {

  33. position: relative;

  34. width: 300px;

  35. height: 300px;

  36. box-sizing: border-box;

  37. filter: blur(8px);


  38. &::after {

  39. content: "";

  40. position: absolute;

  41. top: 40%;

  42. left: 50%;

  43. transform: translate(-50%, -50%) rotate(0);

  44. width: 200px;

  45. height: 200px;

  46. background-color: #00ff6f;

  47. border-radius: 42% 38% 62% 49% / 45%;

  48. animation: rotate 10s infinite linear;

  49. }


  50. &::before {

  51. content: "";

  52. position: absolute;

  53. width: 176px;

  54. height: 176px;

  55. top: 40%;

  56. left: 50%;

  57. transform: translate(-50%, -50%);

  58. border-radius: 50%;

  59. background-color: #000;

  60. z-index: 10;

  61. }

  62. }


  63. .g-bubbles {

  64. position: absolute;

  65. left: 50%;

  66. bottom: 0;

  67. width: 100px;

  68. height: 40px;

  69. transform: translate(-50%, 0);

  70. border-radius: 100px 100px 0 0;

  71. background-color: #00ff6f;

  72. filter: blur(5px);

  73. }


  74. li {

  75. position: absolute;

  76. border-radius: 50%;

  77. background: #00ff6f;

  78. }


  79. @for $i from 0 through 15 {

  80. li:nth-child(#{$i}) {

  81. $width: 15 + random(15) + px;

  82. left: 15 + random(70) + px;

  83. top: 50%;

  84. transform: translate(-50%, -50%);

  85. width: $width;

  86. height: $width;

  87. animation: moveToTop #{random(6) + 3}s ease-in-out -#{random(5000)/1000}s infinite;

  88. }

  89. }


  90. @keyframes rotate {

  91. 50% {

  92. border-radius: 45% / 42% 38% 58% 49%;

  93. }

  94. 100% {

  95. transform: translate(-50%, -50%) rotate(720deg);

  96. }

  97. }


  98. @keyframes moveToTop {

  99. 90% {

  100. opacity: 1;

  101. }

  102. 100% {

  103. opacity: .1;

  104. transform: translate(-50%, -180px);

  105. }

  106. }


  107. @keyframes hueRotate {

  108. 100% {

  109. filter: contrast(15) hue-rotate(360deg);

  110. }

  111. }

知识点

拆解一下知识点,最主要的其实是用到了 filter: contrast() 以及 filter: blur() 这两个滤镜,可以很好的实现这种融合效果。

单独将两个滤镜拿出来,它们的作用分别是:

但是,当他们“合体”的时候,产生了奇妙的融合现象。

先来看一个简单的例子:

仔细看两圆相交的过程,在边与边接触的时候,会产生一种边界融合的效果,通过对比度滤镜把高斯模糊的模糊边缘给干掉,利用高斯模糊实现融合效果。

当然,这种效果在之前的文章也多次提及过,更具体的,可以看看:

颜色的变换

当然,这里也是可以加上颜色的变换,效果也很不错:

  1. html,

  2. body {

  3. width: 100%;

  4. height: 100%;

  5. display: flex;

  6. background: #000;

  7. overflow: hidden;

  8. }


  9. .g-number {

  10. position: absolute;

  11. width: 300px;

  12. top: 27%;

  13. text-align: center;

  14. font-size: 32px;

  15. z-index: 10;

  16. color: #fff;

  17. }


  18. .g-container {

  19. position: relative;

  20. width: 300px;

  21. height: 400px;

  22. margin: auto;

  23. }


  24. .g-contrast {

  25. filter: contrast(15) hue-rotate(0);

  26. width: 300px;

  27. height: 400px;

  28. background-color: #000;

  29. overflow: hidden;

  30. animation: hueRotate 10s infinite linear;

  31. }


  32. .g-circle {

  33. position: relative;

  34. width: 300px;

  35. height: 300px;

  36. box-sizing: border-box;

  37. filter: blur(8px);


  38. &::after {

  39. content: "";

  40. position: absolute;

  41. top: 40%;

  42. left: 50%;

  43. transform: translate(-50%, -50%) rotate(0);

  44. width: 200px;

  45. height: 200px;

  46. background-color: #00ff6f;

  47. border-radius: 42% 38% 62% 49% / 45%;

  48. animation: rotate 10s infinite linear;

  49. }


  50. &::before {

  51. content: "";

  52. position: absolute;

  53. width: 176px;

  54. height: 176px;

  55. top: 40%;

  56. left: 50%;

  57. transform: translate(-50%, -50%);

  58. border-radius: 50%;

  59. background-color: #000;

  60. z-index: 10;

  61. }

  62. }


  63. .g-bubbles {

  64. position: absolute;

  65. left: 50%;

  66. bottom: 0;

  67. width: 100px;

  68. height: 40px;

  69. transform: translate(-50%, 0);

  70. border-radius: 100px 100px 0 0;

  71. background-color: #00ff6f;

  72. filter: blur(5px);

  73. }


  74. li {

  75. position: absolute;

  76. border-radius: 50%;

  77. background: #00ff6f;

  78. }


  79. @for $i from 0 through 15 {

  80. li:nth-child(#{$i}) {

  81. $width: 15 + random(15) + px;

  82. left: 15 + random(70) + px;

  83. top: 50%;

  84. transform: translate(-50%, -50%);

  85. width: $width;

  86. height: $width;

  87. animation: moveToTop #{random(6) + 3}s ease-in-out -#{random(5000)/1000}s infinite;

  88. }

  89. }


  90. @keyframes rotate {

  91. 50% {

  92. border-radius: 45% / 42% 38% 58% 49%;

  93. }

  94. 100% {

  95. transform: translate(-50%, -50%) rotate(720deg);

  96. }

  97. }


  98. @keyframes moveToTop {

  99. 90% {

  100. opacity: 1;

  101. }

  102. 100% {

  103. opacity: .1;

  104. transform: translate(-50%, -180px);

  105. }

  106. }


  107. @keyframes hueRotate {

  108. 100% {

  109. filter: contrast(15) hue-rotate(360deg);

  110. }

  111. }

容易忽视的点

通过调节 filter: blur() 及 filter: contrast() 属性的值,动画效果其实会有很大程度的变化,好的效果需要不断的调试。当然,经验在其中也是发挥了很重要的作用,说到底还是要多尝试。

最后

本文给出的几个充电动画,效果渐进增强,本文只指出了最核心的知识点。但是在实际输出的过程中有很多小细节是本文没有提及的,感兴趣的同学还是应该点进 Demo 好好看看源码或者自己动手实现一遍。

CSS 奇技淫巧GitHub:https://github.com/chokcoco/iCSS

关于本文 作者:@chokcoco 原文:https://juejin.im/post/5e00240ee51d45583c1cc9a7

@chokcoco曾分享过


【第1568期】CSS 火焰


【第1503期】不可思议的纯 CSS 滚动进度条效果


为你推荐


【第1073期】巧用匿名函数重构你的代码


【第1815期】利用 JS 实现多种图片相似度算法


最后,【活动】SEE Conf 大会邀请函:体验美好,玩转数据 会将在B站和优酷直播,有兴趣的童鞋赶紧去订阅


https://live.bilibili.com/21726701?visit_id=80rlef5lczr4

https://vku.youku.com/live/ilproom?id=8031652