纯 CSS 实现科技感十足的暗黑字符雨动画

发表于 3年以前  | 总阅读数:310 次

本文将使用纯 CSS,带大家一步一步实现一个这样的科幻字符跳动背景动画。类似于这样的字符雨动画:

Digital Char Rain Animation

或者是类似于这样的:

CodePen Home Matrix digital rain (animated version) By yuanchuan

运用在一些类似科技主题的背景之上,非常的添彩。

文字的竖排

首先第一步,就是需要实现文字的竖向排列:

这一步非常的简单,可能方法也很多,这里我简单罗列一下:

  1. 使用控制文本排列的属性 writing-mode 进行控制,可以通过 writing-mode: vertical-lr 等将文字进行竖向排列,但是对于数字和英文,将会旋转 90° 展示:
<p>1234567890ABC</p>
<p>中文或其他字符ォヶ</p>
p {
    writing-mode: vertical-lr; 
}

当然这种情况下,英文字符的展示不太满足我们的需求。

2 . 控制容器的宽度,控制每行只能展示 1 个中文字符。

这个方法算是最简单便捷的方法了,但是由于英文的特殊性,要让连续的长字符串自然的换行,我们还需要配合 word-break: break-all

p {
    width: 12px;
    font-size: 10px;
    word-break: break-all;
}

效果如下,满足需求:

使用 CSS 实现随机字符串的选取

为了让我们的效果更加自然。每一列的字符的选取最好是随机的。

但是要让 CSS 实现随机生成每一列的字符可太难了。所以这里我们请出 CSS 预处理器 SASS/LESS 。

而且由于不太可能利用 CSS 给单个标签内,譬如 标签插入字符,所以我们把标签内的字符展示,放在每个 元素的伪元素 ::beforecontent 当中。

我们可以提前设置好一组字符串,然后利用 SASS function 随机生成每一次元素内的 content,伪代码如下:

<div>
    <p></p>
    <p></p>
    <p></p>
</div>
$str: 'ぁぃぅぇぉかきくけこんさしすせそた◁▣▤▥▦▧♂♀♥☻►◄▧▨♦ちつってとゐなにぬねのはひふへほゑまみむめもゃゅょゎをァィゥヴェォカヵキクケヶコサシスセソタチツッテトヰンナニヌネノハヒフヘホヱマミムメモャュョヮヲㄅㄉㄓㄚㄞㄢㄦㄆㄊㄍㄐㄔㄗㄧㄛㄟㄣㄇㄋㄎㄑㄕㄘㄨㄜㄠㄤㄈㄏㄒㄖㄙㄩㄝㄡㄥabcdefghigklmnopqrstuvwxyz123456789%@#$<>^&*_+';
$length: str-length($str);

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

p:nth-child(1)::before {
    content: randomChars(25);
}
p:nth-child(2)::before {
    content: randomChars(25);
}
p:nth-child(3)::before {
    content: randomChars(25);
}

简单解释下上面的代码:

  1. $str 定义了一串随机字符串,$length 表示字符串的长度
  2. randomChar() 中利用了 SASS 的 random() 方法,每次随机选取一个 0 - $length 的整形数,记为 $r,再利用 SASS 的 str-slice 方法,每次从 $str 中选取一个下标为 $r 的随机字符
  3. randomChars() 就是循环调用 randomChar() 方法,从 $str 中随机生成一串字符串,长度为传进去的参数 $number

这样,每一列的字符,每次都是不一样的:

当然,上述的方法我认为不是最好的,CSS 的伪元素的 content 是支持字符编码的,譬如 content: '\3066'; 会被渲染成字符 ,这样,通过设定字符区间,配合 SASS function 可以更好的生成随机字符,但是我尝试了非常久,SASS function 生成的最终产物会在 \3066 这样的数字间添加上空格,无法最终通过字符编码转换成字符,最终放弃...

使用 CSS 实现打字效果

OK,继续,接下来我们要使用 CSS 实现打字效果,就是让字符一个一个的出现,像是这样:

纯 CSS 实现文字输入效果

这里借助了 animation 的 steps 的特性实现,也就是逐帧动画。

从左向右和从上向下原理是一样的,以从左向右为例,假设我们有 26 个英文字符,我们已知 26 个英文字符组成的字符串的长度,那么我们只需要设定一个动画,让它的宽度变化从 0 - 100% 经历 26 帧即可,配合 overflow: hidden,steps 的每一帧即可展出一个字符。

当然,这里需要利用一些小技巧,我们如何通过字符的数量知道字符串的长度呢?

划重点:通过等宽字体的特性,配合 CSS 中的 ch 单位

如果不了解什么是等宽字体族,可以看看我的这篇文章 -- 《你该知道的字体 font-family》[1]。

CSS 中,ch 单位表示数字 “0” 的宽度。如果字体恰巧又是等宽字体,即每个字符的宽度是一样的,此时 ch 就能变成每个英文字符的宽度,那么 26ch 其实也就是整个字符串的长度。

利用这个特性,配合 animation 的 steps,我们可以轻松的利用 CSS 实现打字动画效果:

<h1>Pure CSS Typing animation.</h1>
h1 {
    font-family: monospace;
    width: 26ch;
    white-space: nowrap;
    overflow: hidden;
    animation: typing 3s steps(26, end);
}

@keyframes typing {
    0{
        width: 0;
    }
    100% {
        width: 26ch;
     }
}

就可以得到如下结果啦:

纯 CSS 实现文字输入效果

完整的代码你可以戳这里:

CodePen Demo -- 纯 CSS 实现文字输入效果[2]

改造成竖向打字效果

接下来,我们就运用上述技巧,改造一下。将一个横向的打字效果改造成竖向的打字效果。

核心的伪代码如下:

<div>
    <p></p>
    <p></p>
    <p></p>
</div>
$str: 'ぁぃぅぇぉかきくけこんさしすせそた◁▣▤▥▦▧♂♀♥☻►◄▧▨♦ちつってとゐなにぬねのはひふへほゑまみむめもゃゅょゎをァィゥヴェォカヵキクケヶコサシスセソタチツッテトヰンナニヌネノハヒフヘホヱマミムメモャュョヮヲㄅㄉㄓㄚㄞㄢㄦㄆㄊㄍㄐㄔㄗㄧㄛㄟㄣㄇㄋㄎㄑㄕㄘㄨㄜㄠㄤㄈㄏㄒㄖㄙㄩㄝㄡㄥabcdefghigklmnopqrstuvwxyz123456789%@#$<>^&*_+';
$length: str-length($str);

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

p {
    width: 12px;
    font-size: 10px;
    word-break: break-all;
}

p::before {
    content: randomChars(20);
    color: #fff;
    animation: typing 4s steps(20, end) infinite;
}

@keyframes typing {
    0% {
        height: 0;
    }
    25% {
        height: 100%;
    }
    100% {
        height: 100%;
    }
}

这样,我们就实现了竖向的打字效果:

当然,这样看上去比较整齐划一,缺少了一定的随机,也就缺少了一定的美感。

基于此,我们进行 2 点改造:

  1. 基于动画的时长 animation-time、和动画的延迟 animation-delay,增加一定幅度内的随机
  2. 在每次动画的末尾或者过程中,重新替换伪元素的 content,也就是重新生成一份 content

可以借助 SASS 非常轻松的实现这一点,核心的 SASS 代码如下:

$n: 3;
$animationTime: 3;
$perColumnNums: 20;

@for $i from 0 through $n {
    $content: randomChars($perColumnNums);
    $contentNext: randomChars($perColumnNums);
    $delay: random($n);
    $randomAnimationTine: #{$animationTime + random(20) / 10 - 1}s;

    p:nth-child(#{$i})::before {
        content: $content;
        color: #fff;
        animation: typing-#{$i} $randomAnimationTine steps(20, end) #{$delay * 0.1s * -1} infinite;
    }

    @keyframes typing-#{$i} {
        0% {
            height: 0;
        }
        25% {
            height: 100%;
        }
        100% {
            height: 100%;
            content: $contentNext;
        }
    }
}

看看效果,已经有不错的改观:

当然,上述由横向打字转变为竖向打字效果其实是有一些不一样的。在现有的竖向排列规则下,无法通过 ch 配合字符数拿到实际的竖向高度。所以这里有一定的取舍,实际放慢动画来看,没个字的现出不一定是完整的。

当然,在快速的动画效果下几乎是察觉不到的。

增加光影与透明度变化

最后一步,就是增加光影及透明度的变化。

最佳的效果是要让每个新出现的字符保持亮度最大,同时已经出现过的字符亮度慢慢减弱。

但是由于这里我们无法精细操控每一个字符,只能操控每一行字符,所以在实现方式上必须另辟蹊径。

最终的方式是借用了另外一个伪元素进行同步的遮罩以实现最终的效果。下面我们就来一步一步看看过程。

给文字增添亮色及高光

第一步就是给文字增添亮色及高光,这点非常容易,就是选取一个黑色底色下的亮色,并且借助 text-shadow 让文字发光。

p::before {
    color: rgb(179, 255, 199);
    text-shadow: 0 0 1px #fff, 0 0 2px #fff, 0 0 5px currentColor, 0 0 10px currentColor;
}

看看效果,左边是白色字符,中间是改变字符颜色,右边是改变了字体颜色并且添加了字体阴影的效果:

给文字添加同步遮罩

接下来,就是在文字动画的行进过程中,同步添加一个黑色到透明的遮罩,尽量还原让每个新出现的字符保持亮度最大,同时已经出现过的字符亮度慢慢减弱。

这个效果的示意图大概是这样的,这里我将文字层和遮罩层分开,并且底色从黑色改为白色,方便理解:

蒙层遮罩原理图大概的遮罩的层的伪代码如下,用到了元素的另外一个伪元素:

p::after {
    content: '';
    background: linear-gradient(rgba(0, 0, 0, .9), transparent 75%, transparent);
    background-size: 100% 220%;
    background-repeat: no-repeat;
    animation: mask 4s infinite linear;
}

@keyframes mask {
    0% {
        background-position: 0 220%;
    } 
    30% {
        background-position: 0 0%;
    }
    100% {
        background-position: 0 0%;
    }
}

好,合在一起的最终效果大概就是这样:

通过调整 @keyframes mask 的一些参数,可以得到不一样的字符渐隐效果,需要一定的调试。

完整代码及效果

OK,拆解了一下主要的步骤,最后上一下完整代码,应用了 Pug 模板引擎和 SASS 语法。

完整代码加起来不过 100 行。

.g-container
    -for(var i=0; i<50; i++)
        p
@import url('https://fonts.googleapis.com/css2?family=Inconsolata:wght@200&display=swap');

$str: 'ぁぃぅぇぉかきくけこんさしすせそた◁▣▤▥▦▧♂♀♥☻►◄▧▨♦ちつってとゐなにぬねのはひふへほゑまみむめもゃゅょゎをァィゥヴェォカヵキクケヶコサシスセソタチツッテトヰンナニヌネノハヒフヘホヱマミムメモャュョヮヲㄅㄉㄓㄚㄞㄢㄦㄆㄊㄍㄐㄔㄗㄧㄛㄟㄣㄇㄋㄎㄑㄕㄘㄨㄜㄠㄤㄈㄏㄒㄖㄙㄩㄝㄡㄥabcdefghigklmnopqrstuvwxyz123456789%@#$<>^&*_+';
$length: str-length($str);
$n: 50;
$animationTime: 4;
$perColumnNums: 25;

@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;
    display: flex;
    overflow: hidden;
}

.g-container {
    width: 100vw;
    display: flex;
    justify-content: space-between;
    flex-wrap: nowrap;
    flex-direction: row;
    font-family: 'Inconsolata', monospace, sans-serif;
}

p {
    position: relative;
    width: 5vh;
    height: 100vh;
    text-align: center;
    font-size: 5vh;
    word-break: break-all;
    white-space: pre-wrap;

    &::before,
    &::after {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        height: 100%;
        overflow: hidden;
    }
}

@for $i from 0 through $n {
    $content: randomChars($perColumnNums);
    $contentNext: randomChars($perColumnNums);
    $delay: random($n);
    $randomAnimationTine: #{$animationTime + random(20) / 10 - 1}s;

    p:nth-child(#{$i})::before {
        content: $content;
        color: rgb(179, 255, 199);
        text-shadow: 0 0 1px #fff, 0 0 2px #fff, 0 0 5px currentColor, 0 0 10px currentColor;
        animation: typing-#{$i} $randomAnimationTine steps(20, end) #{$delay * 0.1s * -1} infinite;
        z-index: 1;
    }

    p:nth-child(#{$i})::after {
        $alpha: random(40) / 100 + 0.6;
        content: '';
        background: linear-gradient(rgba(0, 0, 0, $alpha), rgba(0, 0, 0, $alpha), rgba(0, 0, 0, $alpha), transparent 75%, transparent);
        background-size: 100% 220%;
        background-repeat: no-repeat;
        animation: mask $randomAnimationTine infinite #{($delay - 2) * 0.1s * -1} linear;
        z-index: 2;
    }

    @keyframes typing-#{$i} {
        0% {
            height: 0;
        }
        25% {
            height: 100%;
        }
        100% {
            height: 100%;
            content: $contentNext;
        }
    }
}

@keyframes mask{
    0% {
        background-position: 0 220%;
    } 
    30% {
        background-position: 0 0%;
    }
    100% {
        background-position: 0 0%;
    }
}

最终效果也就是题图所示:

Digital Char Rain Animation

完整的代码及演示效果你可以戳这里:

CodePen Demo -- Digital Char Rain Animation[3]

本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/EwTkxij4YjmMAZAzZU0L2w

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237231次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8065次阅读
 目录