我的小册 《CSS 技术揭秘与实战通关》上线了,想了解更多有趣、进阶、系统化的 CSS 内容,可以猛击 - LINK

最近大家刷抖音,是否有刷到拉斯维加斯的新地标 「Sphere」:

场馆内部的视觉效果非常惊人,其中一个效果让我虎躯一震:

我的第一想法就是,这个看起来用 CSS 也可以实现嘛?还有 CSS 不能实现的?

本文,就将尝试使用 CSS,大致还原这个效果。

拆解动画效果

其实,上述的动画效果,本质就是一个 3D 立方体。

同时,3D 立方体上每个面存在颜色不一样的文字,文字和颜色都在随机变化。

也就是说,我们需要实现一个 3D 立方体:

同时,我们还需要实现这样一个动画效果 -- 文字和颜色都在随机变化的平面效果:

两者组合一下,再挪动 3D 元素的景深距离,就能实现我们想要的效果!

好,下面我们一个一个实现。

实现一个 3D 立方体

实现一个 3D 立方体,相对另外一个文字和颜色都在随机变化的平面效果而言,属于非常非常简单的一步了。

我们在非常多篇文章中也讲过具体的实现方式:

最常见的 3D 图形,莫过于一个 3D 立方体。

如果没有上下两个面,只是一个 4 个面的图形,大概是这样:

这样一个图形,利用 CSS 3D,如何快速实现呢?

首先,构造这么一个结构:

<div class="perspective">
<div class="container">
<div class="img">3</div>
<div class="img">D</div>
<div class="img">视</div>
<div class="img">图</div>
</div>
</div>

4 个面,就是最内层的 4 个 .img,首先,需要给两个父容器,设置 3D 的属性:

.perspective {
perspective: 3000px;
}
.container {
width: 400px;
height: 400px;
transform-style: preserve-3d;
}

简单解释一下:

  1. perspective 可以作用于元素的后代,设置在最上层即可;
  2. transform-style: preserve-3d 设置给最终需要 3D 空间的元素的父容器之上,由于最终是 4 个 .img 需要 3D 空间,因此设置给 .container 即可。

接下来,就是最为核心的,如何设置 4 个 .img 元素的 3D 变换,使之形成 3D 立方体。

技巧就是:先旋转,再位移

这里给出一个俯视效果图:

以上述 Demo 中的正方体为例子,class 为 .img 的 div 块的高宽为 400px*400px。那么要利用 4 个 这样的 div 拼接成一个正方体,需要分别将 4 个 div 绕 Y 轴旋转 [90°, 180°, 270°, 360°],再 translateY(200px)

值得注意的是,一定是先旋转角度,再偏移距离,这个顺序很重要

代码如下:

.img {
position: absolute;
top: 0;
left: 0;
width: 400px;
height: 400px;
}
@for $i from 1 through $imgCount {
.img:nth-child(#{$i}) {
transform: rotateY(($i * 90deg)) translateZ(200px);
}
}

效果如下:

此时,可能会觉得图片太太太大了,此时,我们可以通过给中间层 .container 设置一个恰当的 translateZ 进行视觉大小上的调节。

.container {
transform: translateZ(-3000px);
}

这样,就能得到恰当大小的立方体元素效果:

完整的代码,你可以戳这里:CodePen Demo -- 3D Cube

当然,对于我们这个效果,我们 5 要五个面(前后左右与上方即可),因此,我们基于上述的基础知识铺垫,重新实现一个我们需要的框架结构:

<div class="perspective">
<div class="container">
<div class="g-panel"></div>
<div class="g-panel"></div>
<div class="g-panel"></div>
<div class="g-panel"></div>
<div class="g-panel"></div>
</div>
</div>

并且,我们希望我们的图形是一个立方体,只需要稍微改造长宽和 translateZ() 的即可。这样,我们就能得到一个前后左右与上方 5 个面的立方体元素。

示意效果如下:

实现文字动画效果

OK,立方体我们先放在一边。

接下来,我们尝试来实现这个效果:

这个效果如果一个文字用一个 DIV 承载实现,那是非常容易的,但是这样势必会造成元素过多,再设置动画效果,则会导致页面太为卡顿

所以,我们需要另辟蹊径。这里,我们可以使用多层渐变配合 background-clip: text

首先,我们利用等宽字体,随机实现一列文字:

<div>ABCDEFGHIJKLMN</div>
div {
font-family: monospace;
text-align: center;
font-size: 25px;
width: 25px;
line-height: 25px;
color: #fff;
}

效果大致如下:

此时,如果我们再利用线性渐变,给每个字符的对应空间(也就 25px x 25px),设置上不同的颜色,大概是这样:

@function randomLinear($count) {
$value: ''; @for $i from 0 through ($count - 1) {
$value: $value + randomColor() + string.unquote(" 0 #{$i * 25}px,");
} @return linear-gradient(string.unquote(#{$value}) randomColor() 0 100%);
}
@function randomColor() {
@return rgb(randomNum(255), randomNum(255), randomNum(255));
}
div {
// ...
background: randomLinear(14);
}

其中,randomLinear(14) 是一个 SASS 函数,参数 14 表示生成 14 层线性渐变,每一个文字区域的颜色都是随机的,经过编译后的其中一种结果如下:

div {
// ...
background: linear-gradient(#feea96 0 25px, #edde42 0 50px, #e2344a 0 75px, #cdab7e 0 100px, #e16c8b 0 125px, #dcdc7d 0 150px, #dcb42a 0 175px, #d6a587 0 200px, #984f71 0 225px, #221e34 0 250px, #5e9a69 0 275px, #a955e4 0 300px, #4e908f 0 325px, #8d177e 0 350px);
}

上面,我们按照每间隔 25px 的高度,利用线性渐变随机设置了一种颜色,最终,能够得到这么个效果:

此时,我们只需要再设置 background-clip: text,配合透明文字颜色 color: transparent,就可以实现单个 div 内,单列文字,每个字体的颜色都是不一样的:

div {
// ...
background: randomLinear(14);
background-clip: text;
color: transparent;
}

此时,效果如下:

当然,文字颜色可以随机,那么文字本身也应该随机。这个不难,我们也可以借助 SASS 函数,编写一个随机字符的函数,通过元素的伪元素 content 进行设置。

那么此时,完整的代码可能是这样的:

<div></div>
$str: 'QWERTYUIOPASDFGHJKLZXCVBNMabcdefghigklmnopqrstuvwxyz123456789';
$length: str-length($str); @function randomLinear($count) {
$value: ''; @for $i from 0 through ($count - 1) {
$value: $value + randomColor() + string.unquote(" 0 #{$i * 25}px,");
} @return linear-gradient(string.unquote(#{$value}) randomColor() 0 100%);
}
@function randomColor() {
@return rgb(randomNum(255), randomNum(255), randomNum(255));
}
@function randomChar() {
$r: random($length);
@return str-slice($str, $r, $r);
}
@function randomChars($number) {
$value: ''; @if $number > 0 {
@for $i from 1 through $number {
$value: $value + randomChar();
}
}
@return $value;
} div {
position: relative;
width: 25px;
height: 350px; &::before {
content: randomChars(14);
position: absolute;
font-family: monospace;
background: randomLinear(14);
background-clip: text;
color: transparent;
text-align: center;
font-size: 25px;
width: 25px;
line-height: 25px;
}
}

这样,每次 div 内的文字,都是从上面 SASS 函数中 $str 变量中随机取的:

接下来,我们需要实现文字的随机跳变,也很好做,我们需要在一开始,随机生成多个不同的 content,然后,借助 CSS 动画,进行切换。

div {
&::before {
content: randomChars(14);
--content1: "#{randomChars(14)}";
--content2: "#{randomChars(14)}";
--content3: "#{randomChars(14)}";
--content4: "#{randomChars(14)}";
animation: contentChange 1s infinite;
}
} @keyframes contentChange {
20% {
content: var(--content1);
}
40% {
content: var(--content2);
}
60% {
content: var(--content3);
}
80% {
content: var(--content4);
}
}

这里,我们一次生成了 5 个 content,其中 4 个用 CSS 变量保存了起来,随后,在 CSS 动画中,利用提前生成好的 content,进行字符内容的替换,此时,整个效果如下:

随机内容有了,单个字体颜色不一样有了,就差颜色的随机跳变动画了,这个也非常好做,我们在多篇文章也提及过,利用 filter: hue-rotate() 可以快速实现内容的颜色切换。

div {
animation: colorChange 1s steps(12) infinite;
}
@keyframes colorChange {
100% {
filter: hue-rotate(360deg);
}
}

我们利用了 filter: hue-rotate() 加上了步骤动画(steps),成功的实现了颜色的跳变!效果如下:

当然,我们最终要实现的是整个面随机颜色加上随机文字的跳变动画,只需要在上述的基础上,利用 SASS 函数,循环重复多列操作即可。基于上述所有内容的铺垫,我们最终的单个面下的动画效果代码如下:


<div class="g-container">
<div></div>
// ... 一个 32 个子 div
<div></div>
</div>
@use "sass:string";

$str: 'QWERTYUIOPASDFGHJKLZXCVBNMabcdefghigklmnopqrstuvwxyz123456789';
$length: str-length($str);
$size: 25;
$count: 41; @function randomNum($max, $min: 0, $u: 1) {
@return ($min + random($max)) * $u;
} @function randomLinear($count) {
$value: ''; @for $i from 0 through ($count - 1) {
$value: $value + randomColor() + string.unquote(" 0 #{$i * 25}px,");
} @return linear-gradient(string.unquote(#{$value}) randomColor() 0 100%);
} @function randomColor() {
@return rgb(randomNum(255), randomNum(255), randomNum(255));
} @function randomChar() {
$r: random($length);
@return str-slice($str, $r, $r);
} @function randomChars($number) {
$value: ''; @if $number > 0 {
@for $i from 1 through $number {
$value: $value + randomChar();
}
}
@return $value;
} body,
html {
width: 100%;
height: 100%;
background: #000;
font-family: monospace;
} .g-container {
position: relative;
width: 800px;
height: 800px;
display: flex;
animation: colorChange 1s steps(12) infinite; div {
position: relative;
width: #{$size}px;
height: 800px;
flex-shrink: 0; &::before {
position: absolute;
inset: 0;
text-align: center;
font-size: #{$size}px;
width: #{$size}px;
text-align: center;
line-height: #{$size}px;
color: transparent;
}
} @for $i from 1 to $count {
div:nth-child(#{$i}) {
&::before {
content: randomChars(32);
--content1: "#{randomChars(32)}";
--content2: "#{randomChars(32)}";
--content3: "#{randomChars(32)}";
--content4: "#{randomChars(32)}";
animation: contentChange 1s infinite;
background: randomLinear(32);
background-clip: text;
}
}
}
}
@keyframes colorChange {
100% {
filter: hue-rotate(360deg);
}
}
@keyframes contentChange {
20% {
content: var(--content1);
}
40% {
content: var(--content2);
}
60% {
content: var(--content3);
}
80% {
content: var(--content4);
}
}

这样,我们就成功的实现了单个平面下的,颜色随机,文字随机,且不断变化的动画效果:

单个平面下的完整代码,你可以戳这里:CodePen Demo -- Single Panel Random Text

实现立体效果

有了上面的立方体和单个平面的效果,要实现立体效果就不难了。我们尝试将两者结合起来。

改造原有的立方体结构,大致改成如下形式:

.perspective
.container
.g-panel
-for(var i=0; i<32; i++)
div
.g-panel
-for(var i=0; i<32; i++)
div
.g-panel
-for(var i=0; i<32; i++)
div
.g-panel
-for(var i=0; i<32; i++)
div
.g-panel
-for(var i=0; i<32; i++)
div

上面采用了 PUG 模板引擎来简化代码,编译后的效果如下:

<div class="perspective">
<div class="container">
<div class="g-panel">
<div></div>
// ... 32 个
<div></div>
<div class="g-panel">
<div></div>
// ... 32 个
<div></div>
<div class="g-panel">
<div></div>
// ... 32 个
<div></div>
<div class="g-panel">
<div></div>
// ... 32 个
<div></div>
<div class="g-panel">
<div></div>
// ... 32 个
<div></div>
</div>
</div>

这里,我们只需要实现 5 个面的立方体即可(前后左右以及上方)。

每个 .g-panel,实现一个我们上面铺垫的单面文字跳变效果,这样,我们就能得到这么一个立体的 3D 立方体动画效果:

接下来,我们只需要稍加调试,通过控制 perspectivetransform: translateZ() 控制视觉上的纵深,将画面的视角放置于整个立方体之中,即可得到这么个效果:

好,最后,我们模拟文章开头拉斯维加斯球的效果,让顶部的平面,向下运动,实现一种天花板往下掉的动画效果,最终,我们即可使用纯 CSS,大致模拟出整个效果:

由于 GIF 录制问题,实际效果会比 GIF 展示效果更为震撼。

使用 CSS 实现的完整的代码以及整个效果,你可以点击这里进行查看:CodePen Demo -- Las Vegas Sphere Cube Random Text

最后

本文到此结束,希望对你有帮助

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

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

CSS 还原拉斯维加斯球数字动画的更多相关文章

  1. 用 CSS 实现酷炫的动画充电效果

    巧用 CSS 实现酷炫的充电动画 循序渐进,看看只使用 CSS ,可以鼓捣出什么样的充电动画效果. 画个电池 当然,电池充电,首先得用 CSS 画一个电池,这个不难,随便整一个: 欧了,勉强就是它了. ...

  2. 写css时要注意数字的浮动方向

    写css时要注意数字的浮动方向  当数字位数增加时他的方向才是正确的 text-align:right;padding-right:29px;

  3. 好用的jquery.animateNumber.js数字动画插件

    在做公司的运营报告页面时,有一个数字累计增加的动画效果,一开始,毫无头绪,不知如何下手,于是上网查资料,发现大多都是用的插件来实现的,那么今天,我也来用插件jquery.animateNumber.j ...

  4. 简单css实现input提示交互动画效果

    通过基础CSS实现输入提示交互动画效果,并兼容各浏览器! 1.效果展示 2.css代码 h4 { margin: 30px 0; } input { margin:; font-size: 16px; ...

  5. jquery轻量级数字动画插件jquery.countup.js

    插件描述: jquery.countup.js 是一款轻量级jquery数字动画插件.该数字动画插件可以在页面滚动时,将指定的数字从0开始计数增加动画. 插件说明 jquery.countup.js  ...

  6. js数字动画

    项目中需要的数字动画效果,网上找不到需要的效果,所以自己写了一个. 不多说,直接上干货:

  7. css3-12 transition+css或transform实现过渡动画

    css3-12 transition+css或transform实现过渡动画 一.总结 一句话总结:首先要设置hover后的效果,然后在transition里面指定执行哪些样式和执行时间为多长. 1. ...

  8. 纯CSS制作加<div>制作动画版哆啦A梦

    纯CSS代码加上<div>制作动画版哆啦A梦(机器猫) 哆啦A梦(机器猫)我们大家一定都很熟悉,今天给大家演示怎么用纯CSS代码,来做一个动画版的哆啦A梦. 效果图: ###下面代码同学可 ...

  9. jQuery学习-css、class操作、动画方法的运用、jQ操作Dom节点

    css操作(设置单个/多个样式.获取样式) //修改单个属性:括号之中直接是需要修改的样式名,值 css(name,value) //例:$("#one").css("b ...

  10. 一个CSS+jQuery的放大缩小动画效果

    日期: 2013年9月23日 作者:铁锚 // 今天帮朋友写了一些代码,自己觉得写着写着,好几个版本以后,有点满意,于是就贴出来. // 都是定死了的.因为需求就只有4个元素.如果是要用CSS的cla ...

随机推荐

  1. React组件三大属性state,props,refs

    1. React组件定义 1.1 函数组件(Function Components) 函数组件是一种简单的定义组件的方式,通过一个JavaScript函数来定义组件.函数接收一个props对象作为参数 ...

  2. .Net FrameWork下面如何生成AOT呢?

    前言 其实AOT预编译,在.Net FrameWorker1.0里面就有了.它叫做Ngen,只不过当时叫做生成本机映像,实际上还是一个东西,也就是预编译.本篇来看下. 概括 1.介绍 现在的现代化的. ...

  3. [HUBUCTF 2022 新生赛]simple_RE

    [HUBUCTF 2022 新生赛]simple_RE 查壳,64位 找main函数,F5查看伪代码,简单分析一下 int __cdecl main(int argc, const char **ar ...

  4. Abaqus添加初始缺陷

    主要介绍通过施加节点位移的方法 步骤一: 复制model,新建Step,static linear perturbation Tools->Analytical Field 定义场函数,例如:A ...

  5. Django-4.2博客开发教程:需求分析并确定数据表(四)

    前三步已经完成了一个初步流程,从创建项目>应用>数据迁移>访问首页.以下是我整理的基本流程,接下来一步一步完成整个项目. 1.我们的需求: 博客的功能主要分为:网站首页.文章分类.文 ...

  6. 【MAUI Blazor踩坑日记】3.Windows标题栏自定义颜色,运行时改变颜色

    目录 修改默认颜色 修改运行时颜色 效果图 MAUI中Windows默认的标题栏颜色是灰色的,有一点丑. 如果去掉默认的标题栏,自己画一个,可能会出现问题,也比较麻烦. 想要自定义默认标题栏的颜色,官 ...

  7. EF 管理数据库架构

    本章会主要了解EF提供的独立迁移项目,用独立迁移项目自动创建dgml设计关系图和sql脚本. 迁移项目通常也叫(CodeFirst代码优先),在EF中迁移项目是在,在代码中设计数据库,每次对数据库的设 ...

  8. Django链接数据库出现的错误以及解决方法

    问题一:django.db.utils.OperationalError: (1045, "Access denied for user 'leo'@'localhost' (using p ...

  9. [ABC132D] Blue and Red Balls

    2023-01-16 题目 题目传送门 翻译 翻译 难度&重要性(1~10):3 题目来源 AtCoder 题目算法 dp 解题思路 因为蓝球的数量是固定的,题目让我们求,在取 \(i\) 次 ...

  10. MySQL 慢查询探究分析

    背景: 性能测试过程中,数据库往往是造成性能瓶颈之一,而数据库瓶颈中sql 语句又是值得探究分析的一环,其中慢查询是重点优化对象,在MySQL中,慢查询是指查询执行时间较长或者消耗 较多资源的查询语句 ...