3D 计数器
当然,发挥想象,我们还可以利用 3D 文字效果,制作出非常多有意思的效果。
譬如这个,我之前运用在我们业务的可视化看板项目中的 3D 计数器:
代码比较长,就不贴出来了,但是也是使用纯 CSS 可以实现的效果。
完整的代码,你可以猛击这里 CSS 灵感 -- 3D 数字计数动画
空间效果
嗯,上述章节主要是关于文字的 3D 效果,下面我们继续探寻 3D 在营造空间效果上的神奇之处。
优秀的 3D 效果,能让人有一种身临其境的感觉,都说 CSS 3D 其实作用有限,能做的不多,但是不代表它不能实现酷炫逼真的效果。
要营造逼真的 3D 效果,关键是恰当好处的运用 perspective 属性。
简单掌握原理,我们也可以很轻松的利用 CSS 3D 绘制一些非常有空间美感的效果。
这里我带领大家快速绘制一副具有空间美感的 CSS 3D 作品。
空间 3D 效果热身
首先,我们借助 Grid/Flex 等布局,在屏幕上布满格子(item),随意点就好:
<ul class="g-container"> <li></li> <li></li> // ... 很多子 li <li></li> </ul>
初始背景色为黑色,每个 item 填充为白色
接着,改变下每个 item 的形状,让他变成长条形的,可以改变通过改变 item 宽度,使用渐变填充部分等等方式:
接下来,父容器设置 transform-style: preserve-3d 和 perspective,子元素设置 transform: rotateX(45deg),神奇的事情就发生了:
Wow,仅仅 3 步,我们就初步得到了一副具有空间美感的图形,让我们再回到每个子 item 的颜色设置,给它们随机填充不同的颜色,并且加上一个 transform: translate3d() 的动画,一个简单的 CSS 3D 作品就绘制完成了:
于这个技巧的变形和延伸,我们就可以绘制非常多类似的效果。
在这里,我再次推荐 CSS-Doodle 这个工具,它可以帮助我们快速的创造复杂 CSS 效果。
CSS-doodle 是一个基于 Web-Component 的库。允许我们快速的创建基于 CSS Grid 布局的页面,以实现各种 CSS 效果(或许可以称之为 CSS 艺术)。
我们可以把上述的线条切换成圆弧:
完整的代码可以戳这里,利用 CSS-Doodle 也就几十行:CodePen Demo - CSS-Doodle Random Circle
又譬如袁川老师创作的 Seeding:
利用图片素材
当然,基于上述技巧,有的时候会认为利用 CSS 绘制一些线条、圆弧、方块比较麻烦。可以进一步尝试利用现有的素材基于 CSS 3D 进行二次创作,这里有一个非常有意思的技巧。
假设我们有这样一张图形:
这张图先放着备用。在使用这张图之前,我们会先绘制这样一个图形:
<div class="g-container"> <div class="g-group"> <div class="item item-right"></div> <div class="item item-left"></div> <div class="item item-top"></div> <div class="item item-bottom"></div> <div class="item item-middle"></div> </div> </div>
body { background: #000; } .g-container { position: relative; } .g-group { position: absolute; width: 100px; height: 100px; left: -50px; top: -50px; transform-style: preserve-3d; } .item { position: absolute; width: 100%; height: 100%; background: rgba(255, 255, 255, .5); } .item-right { background: red; transform: rotateY(90deg) translateZ(50px); } .item-left { background: green; transform: rotateY(-90deg) translateZ(50px); } .item-top { background: blue; transform: rotateX(90deg) translateZ(50px); } .item-bottom { background: deeppink; transform: rotateX(-90deg) translateZ(50px); } .item-middle { background: rgba(255, 255, 255, 0.5); transform: rotateX(180deg) translateZ(50px); }
一共设置了 5 个子元素,不过仔细看 CSS 代码,其中 4 个子元素都设置了 rotateX/Y(90deg/-90deg),也就是绕 X 轴或者 Y 轴旋转了 90°,在视觉上是垂直屏幕的一张平面,所以直观视觉上我们是不到的,只能看到一个平面 .item-middle。
我将 5 个子 item 设置了不同的背景色,结果如下:
现在看来,好像平平无奇,确实也是。
不过,见证奇迹的时候来了,此时,我们给父元素 .g-container
设置一个极小的 perspective
,譬如,设置一个 perspective: 4px
,看看效果:
.g-container { position: relative; + perspective: 4px; } // ...其余样式保持不变
此时,画风骤变,整个效果就变成了这样:
由于 perspective 生效,原本的平面效果变成了 3D 的效果。接下来,我们使用上面准备好的星空图,替换一下上面的背景颜色,全部都换成同一张图,神奇的事情发生了:
由于设置的 perspective 非常之下,而每个 item 的 transform: translateZ(50px) 设置的又比较大,所以图片在视觉上被拉伸的非常厉害。但是整体是充满整个屏幕的。
接下来,我们只需要让视角动起来,给父元素增加一个动画,通过控制父元素的 translateZ() 进行变化即可:
.g-container{ position: relative; perspective: 4px; perspective-origin: 50% 50%; } .g-group{ position: absolute; // ... 一些定位高宽代码 transform-style: preserve-3d; + animation: move 8s infinite linear; } @keyframes move { 0%{ transform: translateZ(-50px) rotate(0deg); } 100%{ transform: translateZ(50px) rotate(0deg); } }
看看,神奇美妙的星空穿梭的效果就出来了,Amazing:
美中不足之处在于,动画没能无限衔接上,开头和结尾都有很大的问题。
当然,这难不倒我们,我们可以:
- 通过叠加两组同样的效果,一组比另一组通过负的 animation-delay 提前行进,使两组动画衔接起来(一组结束的时候另外一组还在行进中)
- 再通过透明度的变化,隐藏掉 item-middle 迎面飞来的突兀感
- 最后,可以通过父元素的滤镜 hue-rotate 控制图片的颜色变化
我们尝试修改 HTML 结构如下:
<div class="g-container"> <div class="g-group"> <div class="item item-right"></div> <div class="item item-left"></div> <div class="item item-top"></div> <div class="item item-bottom"></div> <div class="item item-middle"></div> </div> <!-- 增加一组动画 --> <div class="g-group"> <div class="item item-right"></div> <div class="item item-left"></div> <div class="item item-top"></div> <div class="item item-bottom"></div> <div class="item item-middle"></div> </div> </div>
修改后的核心 CSS 如下:
.g-container{ perspective: 4px; position: relative; // hue-rotate 变化动画,可以让图片颜色一直变换 animation: hueRotate 21s infinite linear; } .g-group{ transform-style: preserve-3d; animation: move 12s infinite linear; } // 设置负的 animation-delay,让第二组动画提前进行 .g-group:nth-child(2){ animation: move 12s infinite linear; animation-delay: -6s; } .item { background: url(https://z3.ax1x.com/2021/08/20/fLwuMd.jpg); background-size: cover; opacity: 1; // 子元素的透明度变化,减少动画衔接时候的突兀感 animation: fade 12s infinite linear; animation-delay: 0; } .g-group:nth-child(2) .item { animation-delay: -6s; } @keyframes move { 0%{ transform: translateZ(-500px) rotate(0deg); } 100%{ transform: translateZ(500px) rotate(0deg); } } @keyframes fade { 0%{ opacity: 0; } 25%, 60%{ opacity: 1; } 100%{ opacity: 0; } } @keyframes hueRotate { 0% { filter: hue-rotate(0); } 100% { filter: hue-rotate(360deg); } }
最终完整的效果如下,星空穿梭的效果,整个动画首尾相连,可以一直无限下去,几乎没有破绽,非常的赞:
上述的完整代码,你可以猛击这里:CSS 灵感 -- 3D 宇宙时空穿梭效果
3D 无限延伸视角动画
OK,当掌握了上述技巧之后,我们可以很容易的对其继续变形发散,实现各种各样的无限延伸的 3D 视角动画。
这里还有一个非常有意思的运用了类似技巧的动画:
原理与上述的星空穿梭大致相同,4 面墙的背景图使用 CSS 渐变可以很轻松的绘制出来,接下来就只是需要考虑如何让动画能无限循环下去,控制好首尾的衔接。
该效果最早见于 jkantner 的 CodePen,在此基础上我对其进行了完善和丰富,完整代码,你可以猛击这里:CSS 灵感 -- 3D 无限延伸视角动画
视差效果
由于 CSS 3D 的特性,它天生就非常适合拿来制作一些视差效果。
本章节的内容之前在我的另外一篇文章,也有过一些讨论 -- CSS 实现视差效果
原理就是:
- 我们给容器设置上 transform-style: preserve-3d 和 perspective: [x]px,那么处于这个容器的子元素就将位于3D空间中,
- 再给子元素设置不同的 transform: translateZ(),这个时候,不同元素在 3D Z轴方向距离屏幕(我们的眼睛)的距离也就不一样
- 滚动滚动条,由于子元素设置了不同的 transform: translateZ(),那么他们滚动的上下距离 translateY 相对屏幕(我们的眼睛),也是不一样的,这就达到了滚动视差的效果。
核心代码表示就是:
<div class="g-container"> <div class="section-one">translateZ(-1)</div> <div class="section-two">translateZ(-2)</div> <div class="section-three">translateZ(-3)</div> </div>
html { height: 100%; overflow: hidden; } body { perspective: 1px; transform-style: preserve-3d; height: 100%; overflow-y: scroll; overflow-x: hidden; } .g-container { height: 150%; .section-one { transform: translateZ(-1px); } .section-two { transform: translateZ(-2px); } .section-three { transform: translateZ(-3px); } }
总结就是父元素设置 transform-style: preserve-3d 和 perspective: 1px,子元素设置不同的 transform: translateZ,滚动滚动条,效果如下:
CodePen Demo -- CSS 3D parallax
很明显,当滚动滚动条时,不同子元素的位移程度从视觉上看是不一样的,也就达到了所谓的滚动视差效果。
滚动视差文字阴影/虚影效果/多图展示
那么,运用 translate3d 的视差效果,又能有一些什么好玩的效果呢?下面这个滚动视差文字阴影/虚影效果很有意思:
CodePen Demo -- CSS translate3d Parallax
另外一种就是我们可以把这个技巧运用到类似个人主页,图片展示等一些大屏场景下。
核心就是给每张图片设置不同的 translateZ,给父元素设置一个 persepective 即可,这样,在上下滚动的过程中,就能出现简单的视差效果:
CodePen Demo -- CSS Scroll Parallax Effect
同理,这个滚动视差不仅仅可以作用于上下的滚动,对于左右方向的滚动也是同样生效的:
CodePen Demo -- CSS-Only Horizontal Parallax Gallery By Paulina Hetman
其他实用场景介绍
在这一章节,会介绍一些有趣的,可以落地的 3D 效果或者动画。
404 Rolling Box
在我自己的个人网站的 404 页面,就使用 CSS 3D 实现的立方体制作的一个 404 效果:
其核心就在于在一个 CSS 3D 立方体的基础上:
- 添加立方体的滚动动画
- 控制下落的缓动函数,及落地的震荡动画(为了效果更为逼真,运用了设计动画中的预备动作、跟随和重叠动画等技巧)
- 控制立方体及地面数字画面的平移
- 控制动画的无限循环
整体制作还是非常有难度的,但是用在自己的 404 页面,确实也是非常的酷炫。这个效果,我最早见于 Yusuke Nakaya 大神,完整的代码你可以戳这里:CodePen -- Only CSS: 404 Rolling Box
立方体进度条
嗯,下面这个还是借助了立方体。我们来实现一个立方体进度条~
首先,实现一个立方体,结构如下:
<div class="demo-cube perspective"> <ul class="cube"> <li class="top"></li> <li class="bottom"></li> <li class="front"></li> <li class="back"></li> <li class="right"></li> <li class="left"></li> </ul> </div>
我们可以把这个立方体想象成一个立体的进度条容器,通过控制 6 面的颜色,我们可以巧妙的得到一种 3D 进度条效果。
当然,其实我们不需要那么多面,4 个面即可,去掉左右,然后利用渐变修改一下立方体各个面的颜色,去掉 border,核心的 CSS 代码如下:
.demo-cube { position: relative; .cube { position: absolute; top: 50%; left: 50%; width: 300px; height: 100px; transform-style: preserve-3d; transform: translate(-50%, -50%) rotateX(-33.5deg); li { position: absolute; width: 300px; height: 100px; background: linear-gradient(90deg, rgba(156, 39, 176, .3), rgba(255, 34, 109, .8) 70%, rgba(255, 255, 255, .6) 70%, rgba(255, 255, 255, .6)); } .top { transform: rotateX(90deg) translateZ(50px); } .bottom { transform: rotateX(-90deg) translateZ(50px); } .front { transform: translateZ(50px); } .back { transform: rotateX(-180deg) translateZ(50px); } } }
我们就可以得到一个非常酷炫的 3D 进度条效果:
利用 CSS Property 给 3D 进度条加上动画
当然,进度条嘛,它需要一个填充动画。由于我们使用的是渐变实现的进度条的进度,需要去控制其中的颜色百分比变化。
而正常而言,CSS 是不支持渐变的动画的,不过这也难不倒我们,因为我们可以使用 CSS @Property 。
简单改造一下代码:
@property --per { syntax: '<percentage>'; inherits: false; initial-value: 0%; } .demo-cube .cube { .top, .front, .bottom, .back { background: linear-gradient(90deg, rgba(255, 217, 34, .6), rgba(255, 34, 109, .8) var(--per), rgba(255, 34, 109, .1) var(--per), rgba(255, 34, 109, .1)); animation: perChange 6s infinite; } } @keyframes perChange { 0% { --per: 0%; } 90%, to { --per: 80%; } }
这样,我们就实现了一个会动的 3D 进度条,只需要控制 --per CSS 自定义属性即可,效果如下:
对于 CSS @Property 不算很了解的,可以看看作者的这篇文章 -- CSS @property,让不可能变可能,它的出现,让 CSS 极大的提升了制作各种动画的能力。
上述的完整代码,你可以猛击这里:CSS 灵感 -- 3D 立方体进度条
总结一下
感谢阅读到此,如果认真看完上述内容,相信你一定会惊叹于 CSS 的神奇。希望本文的内容能够让你:
- 了解 CSS 3D 的各种用途
- 激发你新的灵感,感受动画之美
- 提升你的 CSS 动画制作水平
当然,新奇有趣的 CSS 3D 内容还有很多,我还有非常多个有意思的 DEMO 没有贴出来,当然对于本文的内容,我觉得已经足够充实,剩下的下次继续分享。
仅使用 CSS 能制作出多惊艳的动画?我觉得这个问题没有答案,随着 CSS 语言不断发展,各种新特性的持续加入,虽然某些方面比不上一些更专业的语言,但是它也在便利性、易学性上有着自己的优势。