经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » HTML/CSS » CSS » 查看文章
巧用 CSS 变量,实现动画函数复用,制作高级感拉满的网格动画
来源:cnblogs  作者:ChokCoco  时间:2023/3/8 11:00:36  对本文有异议

本文将介绍一种基于 CSS 变量技巧,通过合理使用 CSS 变量,实现 CSS 动画 @keyframes 的复用。

CSS 变量

CSS 变量大家应该都比较熟悉了,已经不能算是新知识了,快速过一遍。

CSS 变量(CSS Variable),在之前也叫做 CSS 自定义属性,其使用方式如下:

  1. // 声明一个变量:
  2. :root{
  3. --bgColor: #000;
  4. }

这里我们借助了上面 #12、结构性伪类 中的 :root{ } 伪类,在全局 :root{ } 伪类中定义了一个 CSS 变量,取名为 --bgColor

定义完了之后则是使用,假设我要设置一个 div 的背景色为黑色:

  1. .main{
  2. background:var(--bgColor);
  3. }

这里,我们在需要使用之前定义变量的地方,通过 var(定义的变量名) 来调用。

在 @keyframes 中使用 CSS 变量

OK,回归我们的正题。巧用 CSS 变量,实现动画函数复用

假设,我们现在有多个元素,需要实现一个位移动画,从位置 A 位移到 位置 B,位置 A 相同,但是位置 B 不一样,像是这样:

正常而言,由于终点不一样,我们可能需要实现 3 个不一样的 @keyframes,像是这样:

  1. <ul>
  2. <li></li>
  3. <li></li>
  4. <li></li>
  5. </ul>
  1. li:nth-child(1) {
  2. animation: move1 2s linear;
  3. }
  4. li:nth-child(2) {
  5. animation: move2 2s linear;
  6. }
  7. li:nth-child(3) {
  8. animation: move3 2s linear;
  9. }
  10. @keyframes move1 {
  11. 60%,
  12. 100% {
  13. transform: translate(150px);
  14. }
  15. }
  16. @keyframes move2 {
  17. 60%,
  18. 100% {
  19. transform: translate(120px);
  20. }
  21. }
  22. @keyframes move3 {
  23. 60%,
  24. 100% {
  25. transform: translate(200px);
  26. }
  27. }

这个代码有问题吗?没有。

但是,我们可以利用 CSS 变量,让它变得更为简洁,我们改造一下 @keyframes 代码,将固定的位移值,变成一个变量:

  1. @keyframes move {
  2. 60%,
  3. 100% {
  4. transform: translate(var(--dis));
  5. }
  6. }

由于 CSS 变量是存在作用域的,我们可以通过 CSS 变量的方式,给每一个 li 定义一个不同的 --dis 变量,像是这样:

  1. li:nth-child(1) {
  2. --dis: 150px;
  3. }
  4. li:nth-child(2) {
  5. --dis: 120px;
  6. }
  7. li:nth-child(3) {
  8. --dis: 200px;
  9. }

这样,虽然动画的结束点不一样,但是我们利用 CSS 变量,复用了同一个 @keyframes 函数:

通过内联 style 属性传入自定义变量

除了通过在 <style> 内传入不同的自定义变量,我们还可以通过内联 style 属性传入自定义变量。

我们再改造一下我们的 @keyframes:

  1. @keyframes move {
  2. 60%,
  3. 100% {
  4. transform: translate(var(--end));
  5. background: var(--color);
  6. }
  7. }

这一次,我们不需要通过 :nth-child() 去修改每一个 li 的 CSS,而是通过 HTML 元素的内联 style 属性,像是这样:

  1. <ul>
  2. <li style="--end: 150px; --color: red;"></li>
  3. <li style="--end: 200px; --color: blue;"></li>
  4. <li style="--end: 120px; --color: green;"></li>
  5. </ul>

是的,每个 li 元素的 @keyframes 可以读取到每个 li 的 style 里面定义的不一样的 CSS 变量。

这样,我们就可以得到如下效果:

完整的代码,可以戳这里:CodePen Demo -- 巧用 CSS 变量,实现动画函数复用

实战演练

下面我们实战演练一下,上一点难度。

在很久之前,我们实现过这样一个动画效果:

这个动画效果的实现方式在于:

  1. 父级元素实现一个 rotateZ(360deg) 的匀速动画
  2. 子级元素实现一个反向的 rotateZ(-360deg) 的匀速动画
  3. 给父级元素添加一个 rotateX(40deg) 的动画

由于父容器和子容器同时相反向旋转,所以子元素看上去其实和没有旋转是一样的。但是由于又添加了一个 rotateX(40deg) 动画,因此看上去就会有这样一种 3D 效果。

在之前,我们的代码是这样的:

  1. <div class="reverseRotate">
  2. <div class="rotate">
  3. </div>
  4. </div>
  1. .rotate {
  2. animation: rotate 5s linear infinite;
  3. }
  4. .reverseRotate {
  5. animation: reverseRotate 5s linear infinite;
  6. }
  7. @keyframes rotate {
  8. 0% {
  9. transform: rotateX(0deg) rotateZ(0deg);
  10. }
  11. 50% {
  12. transform: rotateX(40deg) rotateZ(180deg);
  13. }
  14. 100% {
  15. transform: rotateX(0deg) rotateZ(360deg);
  16. }
  17. }
  18. @keyframes reverseRotate {
  19. 0% {
  20. transform: rotateZ(0deg);
  21. }
  22. 100% {
  23. transform: rotateZ(-360deg);
  24. }
  25. }

可以看到,我们这里实现了两个动画效果:

  1. @keyframes rotate {} 父容器的旋转动画
  2. @keyframes reverseRotate {} 子容器的旋转动画

其实,这里,运用今天的技巧,我们可以把两个动画合成为一个,利用 CSS 自定义变量进行控制。改造后更简洁的 CSS 代码如下:

  1. .rotate {
  2. --degZ: 360deg;
  3. --degZMiddle: 180deg;
  4. --degX: 30deg;
  5. animation: rotate 5s linear infinite;
  6. }
  7. .reverseRotate {
  8. --degZ: -360deg;
  9. --degZMiddle: -180deg;
  10. --degX: 0;
  11. animation: rotate 5s linear infinite;
  12. }
  13. @keyframes rotate {
  14. 0% {
  15. transform: rotateX(0deg) rotateZ(0deg);
  16. }
  17. 50% {
  18. transform: rotateX(var(--degX)) rotateZ(var(--degZMiddle));
  19. }
  20. 100% {
  21. transform: rotateX(0deg) rotateZ(var(--degZ));
  22. }
  23. }

是的,我们可以得到同样的效果!

完整的代码,你可以戳这里:CodePen DEMO -- Css动画正反旋转相消

图片旋转配合容器旋转

下面,我们再来尝试一个有意思的动画效果,图片旋转配合容器旋转。

在上述的基础上,如果我们把子元素,改成图片,整个效果就会有意思不少,我们稍微改变一点点代码:

  1. <div class="reverseRotate">
  2. <img class="rotate" src="https://picsum.photos/1000/1000?random=5" alt="">
  3. </div>
  1. .rotate,
  2. .reverseRotate {
  3. width: 60vh;
  4. height: 60vh;
  5. }
  6. .reverseRotate {
  7. position: absolute;
  8. top: 50%;
  9. left: 50%;
  10. transform: translate(-50%, -50%);
  11. border: 3px solid #999;
  12. overflow: hidden;
  13. }
  14. .rotate {
  15. position: absolute;
  16. top: 50%;
  17. left: 50%;
  18. transform: translate(-50%, -50%);
  19. width: 100%;
  20. height: 100%;
  21. }
  22. .rotate {
  23. --degZ: 360deg;
  24. animation: rotate 5s linear infinite;
  25. }
  26. .reverseRotate {
  27. --degZ: -360deg;
  28. animation: rotate 5s linear infinite;
  29. }
  30. @keyframes rotate {
  31. 0% {
  32. transform: translate(-50%, -50%) rotateZ(0deg);
  33. }
  34. 100% {
  35. transform: translate(-50%, -50%) rotateZ(var(--degZ));
  36. }
  37. }

这里,我们做了什么事情呢?

  1. 去掉了 3D 效果
  2. 给外层容器加了边框
  3. 内层图片基于父容器绝对定位,水平垂直居中
  4. 内外两层容器反向旋转 360° 动画

这样,我们就能看到,虽然内外两层容器同时在进行相反方向的旋转 360° 动画,但是内部的图片其实是静止不动的!

效果如下:

由于,内部图片的大小为父容器的 100%,所以在旋转过程中,父容器会有明显的无法包裹住整个图片的情况。

这个很好解决,我们只需要把图片大小调整大一点:

  1. // ... 其它代码不变
  2. .rotate {
  3. width: 150%;
  4. height: 150%;
  5. }
  6. .rotate {
  7. --degZ: 360deg;
  8. animation: rotate 5s linear infinite;
  9. }

正常而言,对于正方形容器,内部图片设置到 141% 即可满足父容器旋转过程,可以一直包裹住图片的效果。那么,我们就能得到这样一种效果:

完整的代码,你可以戳这里:CodePen Demo -- Css动画正反旋转相消

Gird 布局配合正反旋转动画

当然,上述当只有一个容器的时候,整个动画效果还不够震撼。

如果我们可以把这个效果融合进整个布局的动画之中,整个效果又会完全不一样。

Rotating gallery with CSS scroll-driven animations 这篇文章中,作者提供了一种非常巧妙的思路,将 Grid 布局动画与上述动画效果巧妙的结合了起来。

首先,我们利用 Gird 布局,实现这样一个简单的网格布局结构:

  1. <div class="container">
  2. <div class="A">
  3. <img src="https://picsum.photos/600/600?random=1" alt=""></div>
  4. <div class="B">
  5. <img src="https://picsum.photos/600/600?random=2" alt=""></div>
  6. <div class="C">
  7. <img src="https://picsum.photos/600/600?random=3" alt=""></div>
  8. <div class="D">
  9. <img src="https://picsum.photos/600/600?random=4" alt=""></div>
  10. <div class="E">
  11. <img src="https://picsum.photos/600/600?random=5" alt=""></div>
  12. </div>
  1. .container {
  2. width: 60vmin;
  3. height: 60vmin;
  4. display: grid;
  5. grid-template-columns: 1fr 1fr 1fr;
  6. grid-template-rows: 1fr 1fr 1fr;
  7. gap: 4px;
  8. grid-template-areas:
  9. "E B B"
  10. "E A C"
  11. "D D C";
  12. }
  13. .container > div {
  14. border: 3px solid #431312;
  15. border-radius: 5px;
  16. }
  17. .A {
  18. grid-area: A;
  19. }
  20. .B {
  21. grid-area: B;
  22. }
  23. .C {
  24. grid-area: C;
  25. }
  26. .D {
  27. grid-area: D;
  28. }
  29. .E {
  30. grid-area: E;
  31. }

效果如下:

接下来,我们要做的,就是结合上面的知识点,容器滚动起来,图片反向滚动起来,配合一些 tranfrom 变换。

有了上面的铺垫,下面的新增的代码就非常好理解了:

  1. .container > div img {
  2. --scale: 1;
  3. --rotation: -360deg;
  4. position: absolute;
  5. top: 50%;
  6. left: 50%;
  7. transform: translate(-50%, -50%);
  8. width: 260%;
  9. height: 260%;
  10. object-fit: cover;
  11. object-position: center;
  12. }
  13. .container,
  14. .container > div img {
  15. animation: 10s scale-up both ease-in-out infinite alternate;
  16. }
  17. @keyframes scale-up {
  18. 0% {
  19. transform: translate(-50%, -50%) scale(var(--scale)) rotate(0deg);
  20. }
  21. 100% {
  22. transform: translate(-50%, -50%) scale(1) rotate(var(--rotation));
  23. }
  24. }

这样,我们就得到了一个高级感拉满的网格旋转动画:

注意,这里我们依旧是通过 CSS 自定义变量,在不同元素间,复用了同一个动画 @keyframes 函数。

完整的代码,你可以戳这里:CodePen Demo -- Grid 图片旋转动画 & 使用 CSS 变量复用动画函数

最后

好了,本文到此结束,希望本文对你有所帮助 ??

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

原文链接:https://www.cnblogs.com/coco1s/p/17186878.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号