共计 7124 个字符,预计需要花费 18 分钟才能阅读完成。
本文将应用纯 CSS,带大家一步一步实现一个这样的科幻字符跳动背景动画。相似于这样的字符雨动画:
或者是相似于这样的:
; | |
@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); | |
} |
简略解释下下面的代码:
$str
定义了一串随机字符串,$length
示意字符串的长度- randomChar() 中利用了 SASS 的
random()
办法,每次随机选取一个 0 –$length
的整形数,记为$r
,再利用 SASS 的str-slice
办法,每次从$str
中选取一个下标为$r
的随机字符 - randomChars() 就是循环调用 randomChar() 办法,从
$str
中随机生成一串字符串,长度为传进去的参数$number
这样,每一列的字符,每次都是不一样的:
当然,上述的办法我认为不是最好的,CSS 的伪元素的
content
是反对字符编码的,譬如content: '\3066';
会被渲染成字符て
,这样,通过设定字符区间,配合 SASS function 能够更好的生成随机字符,然而我尝试了十分久,SASS function 生成的最终产物会在\
和3066
这样的数字间增加上空格,无奈最终通过字符编码转换成字符,最终放弃 …
应用 CSS 实现打字成果
OK,持续,接下来咱们要应用 CSS 实现打字成果,就是让字符一个一个的呈现,像是这样:
这里借助了 animation 的 steps
的个性实现,也就是逐帧动画。
从左向右和从上向下原理是一样的,以从左向右为例,假如咱们有 26 个英文字符,咱们已知 26 个英文字符组成的字符串的长度,那么咱们只须要设定一个动画,让它的宽度变动从 0 - 100%
经验 26 帧即可,配合 overflow: hidden
,steps 的每一帧即可展出一个字符。
当然,这里须要利用一些小技巧,咱们如何通过字符的数量晓得字符串的长度呢?
划重点: 通过等宽字体的个性,配合 CSS 中的 ch
单位 。
如果不理解什么是等宽字体族,能够看看我的这篇文章 —《你该晓得的字体 font-family》。
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;} | |
} |
就能够失去如下后果啦:
残缺的代码你能够戳这里:
CodePen Demo — 纯 CSS 实现文字输出成果
革新成竖向打字成果
接下来,咱们就使用上述技巧,革新一下。将一个横向的打字成果革新成竖向的打字成果。
外围的伪代码如下:
<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 点革新:
- 基于动画的时长
animation-time
、和动画的提早animation-delay
,减少肯定幅度内的随机 - 在每次动画的开端或者过程中,从新替换伪元素的
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 |
$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%;} | |
} |
最终成果也就是题图所示:
残缺的代码及演示成果你能够戳这里:
CodePen Demo — Digital Char Rain Animation
最初
灵感源自 袁川 老师的这个成果 CodePen Demo — Matrix digital rain,原成果应用了 JavaScript· 实现,本文利用纯 CSS 进行了演绎。
更多精彩 CSS 成果能够关注我的 CSS 灵感
好了,本文到此结束,心愿对你有帮忙 :)
想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 — iCSS 前端趣闻 😄
更多精彩 CSS 技术文章汇总在我的 Github — iCSS,继续更新,欢送点个 star 订阅珍藏。
如果还有什么疑难或者倡议,能够多多交换,原创文章,文笔无限,满腹经纶,文中若有不正之处,万望告知。