找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5113

积分

0

好友

713

主题
发表于 2 小时前 | 查看: 4| 回复: 0

最近在短视频平台,你很可能刷到过拉斯维加斯的新地标「Sphere」巨型球体。

拉斯维加斯Sphere巨型球体外观

其场馆内部的裸眼3D视觉效果极具冲击力,其中一个动态效果尤其让我印象深刻。

Sphere场馆内部裸眼3D效果

我的第一反应是:这个效果用 CSS 是不是也能模拟出来?毕竟,还有什么是 CSS 不能尝试实现的吗?

本文就将带领大家,一步步使用纯 CSS 技术,大致还原这个震撼的视觉效果。

拆解动画效果

本质上,这个动画是一个动态变化的 3D 立方体。立方体的每个面上,布满了颜色和字符都在随机、快速跳变的“数字雨”或“字符流”。

也就是说,我们需要完成两个核心部分:

  1. 构建一个 3D 立方体。
  2. 实现一个字符和颜色都随机变化的平面动画。

最后将两者结合,并调整 3D 空间的景深和视角,就能逼近目标效果。

好,让我们分步实现。

实现一个 3D 立方体

对于有经验的前端开发者来说,构建一个基础的 3D 立方体是相对简单的任务。在很多探讨 CSS 3D 的文章中都有涉及。

一个最常见的 3D 图形就是立方体。如果先不考虑上下底面,一个只有四个侧面的结构大致像这样:

3D立方体四个侧面示意图

那么,如何用 CSS 3D 快速构建它呢?

首先,准备 HTML 结构:

<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>

四个面就是四个 .img 元素。接着,需要为它们的父级容器设置 3D 相关属性:

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

简单解释一下:

  1. perspective 属性为后代元素设置透视点,放在最外层的 .perspective 上即可。
  2. transform-style: preserve-3d 用于建立 3D 渲染空间。因为最终是 .img 元素需要进行 3D 变换,所以这个属性设置在它们的直接父容器 .container 上。

接下来是关键:如何设置 4 个 .img 的变换,让它们围成一个立方体?核心技巧是:先旋转,再位移

这里有一张俯视图来帮助理解:

3D立方体俯视图及变换参数

假设每个 .img 是一个 400px * 400px 的正方形。要拼成一个立方体,就需要将四个面分别绕 Y 轴旋转 90°、180°、270°、360°(即0°),然后再沿着 Z 轴正向平移 200px(即立方体边长的一半)。

请注意,变换的顺序至关重要,必须是先 rotateY()translateZ()

对应的 CSS 可以这样写(这里使用了 SASS 循环):

.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);
        }
}

效果如下:

旋转并位移后形成的3D立方体框架

此时立方体可能看起来太大。我们可以通过调整中间层 .containertranslateZ 值来改变它在视觉上的大小。

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

这样,就能得到一个大小合适的立方体效果:

调整景深后的3D立方体

完整的代码,你可以戳这里:CodePen Demo -- 3D Cube (Demo 链接在下方参考资料)

当然,为了模拟目标效果,我们需要一个五面体(包含前、后、左、右、上五个面)。基于上面的原理,我们调整一下框架结构:

<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 的距离,就能得到我们所需的五面立方体结构。

示意效果如下:

五面3D立方体线框旋转图

实现文字动画效果

好,立方体部分先放一放。

接下来,我们集中精力实现这个单面的动态效果:

随机字符与颜色的平面动画效果

如果每个字符都用一个独立的 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 * 25px)随机设置不同的颜色。这可以通过 SASS 函数动态生成:

@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) 会生成14层线性渐变,每层对应一个文字高度,颜色随机。编译后的CSS可能像这样:

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);
}

此时,每个高度区间有了不同的颜色背景:

为每行文字设置随机颜色的线性渐变背景

现在,我们只需加上 background-clip: text 并将文字颜色设为透明 color: transparent,就能实现“一列文字,每个字颜色都不同”的效果:

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

效果如下:

应用background-clip: text后的彩色文字效果

文字颜色能随机了,那文字内容本身呢?同样可以随机。我们再编写一个 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 内的文字都是从预设字符集中随机取出的:

单列随机字符效果

接下来是实现文字的随机跳变。思路是:在样式初始化时,就预先生成好几组不同的随机文字内容,存入 CSS 自定义属性(变量)中,然后通过 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组内容(初始1组+4组变量),并在动画中循环切换,这样就得到了文字内容的随机跳变:

文字内容随机跳变动画

还差颜色的随机跳变。这个可以利用 filter: hue-rotate() 滤镜,结合 steps() 步进动画轻松实现。

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

hue-rotate(360deg) 会让颜色色调循环一周,steps(12) 则让这个变化在1秒内分12次跳跃完成,从而实现了颜色的快速跳变效果:

颜色随机跳变动画

当然,我们的目标不是一个单列,而是一个铺满整个面的动画。我们只需要基于上面的逻辑,使用 SASS 循环生成多列(比如32列),并将它们横向排列即可。

基于以上所有铺垫,我们最终实现单个动画平面的核心代码如下:

<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 (Demo 链接在下方参考资料)

实现立体效果

有了上面的立方体和单面动画效果,组合成立体效果就水到渠成了。

改造我们之前的立方体结构,大致如下(这里使用 PUG 模板引擎简化书写):

.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

编译后的 HTML 结构就是:一个立方体容器内,有5个 .g-panel(对应五个面),每个 .g-panel 内包含32个 div,这些 div 将承载我们上面实现的那个单列动画效果。

这样,每个 .g-panel 面都应用了绚丽的随机文字动画,组合起来就得到了一个立体的、五面都在动态变化的 3D 立方体动画:

五面动态变化的3D立方体动画

接下来,我们只需要调整 perspective(透视距离)和 .containertranslateZ(Z轴位移),将观察视角“放置”到这个立方体的内部,就能得到一种被动态字符包围的沉浸感:

调整视角至立方体内部的沉浸式效果

最后,为了模拟文章开头拉斯维加斯球体那种“天花板坠落”的震撼效果,我们可以为顶部的那个平面添加一个向下运动的动画。至此,我们就使用纯 CSS,大致模拟出了整个复杂的视觉效果:

模拟拉斯维加斯球体内部“天花板坠落”的最终动画效果

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

使用纯 CSS 实现的完整代码及效果,你可以点击这里查看:CodePen Demo -- Las Vegas Sphere Cube Random Text (Demo 链接在下方参考资料)

最后

本文通过拆解一个复杂的视觉场景,逐步展示了如何运用 CSS 3D、CSS 动画、SASS 函数式编程以及 background-clip 等特性,将想法变为现实。这再次证明了现代 CSS 在创造丰富视觉体验方面的强大潜力。希望这个实践过程对你有所启发,如果你对这类 前端动效 感兴趣,欢迎在 云栈社区 与其他开发者继续交流探讨。

参考资料

[1] CodePen Demo -- 3D Cube: https://codepen.io/Chokcoco/pen/OJaLLpX
[2] CodePen Demo -- Single Panel Random Text: https://codepen.io/Chokcoco/pen/jOXJqVv?editors=1100
[3] CodePen Demo -- Las Vegas Sphere Cube Random Text: https://codepen.io/Chokcoco/pen/LYMMpPm?editors=1100
[4] Github -- iCSS: https://github.com/chokcoco/iCSS




上一篇:基于Docker与HTTP回调:SRS流媒体服务器推拉流身份认证实战
下一篇:深度剖析PlayStation BD-J沙箱逃逸链:Java权限绕过与Ixc通信漏洞组合利用
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-12 06:55 , Processed in 0.597749 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表