本文将用纯CSS带你一步步实现这样一个科幻角色跳跃的背景动画。类似这个的角色雨动画:DigitalCharRainAnimation或者类似的:CodePenHomeMatrixdigitalrain(animatedversion)byyuanchuan用在一些类似科技题材的背景上,非常出彩。文字竖排第一步是实现文字的竖排:这一步很简单,方法可能有很多,这里我简单罗列一下:1.使用属性writing-mode来控制文字的排列,你可以通过writing-mode:vertical-lr等方式让文字垂直排列,但是对于数字和英文,会旋转90°显示:
1234567890ABC
中文或其他字符ォヶ
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将字符插入到单个标签中,比如一个标签,我们将标签中的字符显示出来,放在每个元素的伪元素::before的内容中。我们可以先使用一个组字符,然后再使用SASS函数生成每个初级元素的内部内容,如下:$str:'AiuuKikukakekonsashisusesota??????♂??????Mamimumemoyuyowawoiewokakekukegakosasissessotatsuttetannanninenenohahifuhehoemamimmemoyowaㄅㄉㄓㄚㄞㄢㄦㄆㄊㄍㄐㄔㄗㄛ??ㄟㄣㄇㄋㄎㄑㄕㄘㄨㄜㄠㄤㄈㄏㄒㄖㄩㄝㄝㄡㄥabcdefghigklmnopqrstuvwxyz<8>$#3456';&$@length:str-length($str);@functionrandomChars(){$r:random($length);@returnstr-slice($str,$r,$r);}@functionrandomChars($number){$value:'';@if$number>0{@for$ifrom1through$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()使用SASSrandom()方法,每time选择一个0-$lengthwell-formednumber,即$r,像str-slice方法一样重用SASS,每次从$str中选择一个Subtitledfor$r字符randomChars()是循环调用randomChar()方法从$str中随机生成一串字符串,长度为传入的参数$number,这样每次每列的字符都不一样:当然,上面的方法我觉得不是最好的。CSS伪元素的内容支持字符编码。例如内容:'\3066';将呈现为字符テ。这样通过设置字符范围,配合SASS功能,可以更好的生成随机字符,不过我试了很久。SASS函数生成的最终产物会在数字之间加上空格,比如\和3066,无法通过字符编码最终转化为字符,最后放弃...用CSS实现打字效果OK,继续,接下来我们用CSS实现打字效果,也就是让字符一个一个出现,像这样:纯CSS实现文字输入效果这里是借助动画步骤的特点实现的,也就是逐帧显示动画从左到右和从上到下的原理是一样的。以从左到右为例。假设我们有26个英文字符,并且知道26个英文字符组成的字符串的长度。那么我们只需要设置一个动画,让它的宽度从0-100%变化到26帧,加上overflow:hidden,每一帧steps可以显示一个字符。当然,我们需要在这里使用一些技巧。我们如何通过字符数知道字符串的长度呢?亮点:通过等宽字体的特性,配合CSS中的ch单元。如果你不知道什么是等宽字体系列,你可以看我的文章——《你该知道的字体 font-family》[1]。在CSS中,ch单位表示数字“0”的宽度。如果字体刚好是等宽字体,即每个字符的宽度都一样,那么ch就可以变成每个英文字符的宽度,那么26ch其实就是整个字符串的长度。利用这个特性,结合动画步骤,我们可以很方便的使用CSS实现打字动画效果:
PureCSSTypinganimation.
h1{font-family:monospace;width:26ch;white-space:nowrap;overflow:hidden;animation:typing3ssteps(26,end);}@keyframestyping{0{width:0;}100%{width:26ch;}},可以得到如下结果:纯CSS实现文字输入效果完整代码,可以点击这里:CodePenDemo——纯CSS实现文字输入效果[2]转化为竖排效果下面我们就用上面的技巧来转化一下。将水平打字效果转换为垂直打字效果。核心笔名如下:$str:'Aiuu????♂??????UennininenenoHahhhhhhhhhhhhhhhhhhhhhhhhhhhhhヮㄅㄅㄞㄞㄢㄢㄦㄦㄆㄧㄧㄣㄇㄣㄇㄋㄎㄑㄕㄕㄨㄨㄜㄜㄙㄒㄤㄩㄩㄡㄥㄡㄥㄡㄥㄡㄥㄡㄥㄡㄥㄡㄥㄡㄥㄡㄥㄡㄥㄡㄥㄡㄥㄡㄥㄡㄥ#$<>^&*_+';$length:str-length($str);@functionrandomChar(){$r:random($length);@returnstr-slice($str,$r,$r);}@functionrandomChars($number){$value:'';@if$number>0{@for$ifrom1through$number{$value:$value+randomChar();}}@return$value;}p{width:12px;font-size:10px;word-break:break-all;}p::before{content:randomChars(20);color:#fff;animation:typing4ssteps(20,end)infinite;}@keyframestyping{0%{height:0;}25%{height:100%;}100%{height:100%;}}这个,我们已经实现了字体的效果:当然,这个和之前的版本一样,稍微固定一下。这是一个完美的契合,它是一种永恒的审美。基于此,我们进行两个改造:基于动画的animation-time和animation-delay,在一定范围内随机增加每个动画末尾或过程中伪元素的内容,即,借助SASS可以很容易地实现重新生成一段内容。核心SASS代码如下:$n:3;$animationTime:3;$perColumnNums:20;@for$ifrom0through$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;动画:打字-#{$i}$randomAnimationTinesteps(20,end)#{$delay*0.1s*-1}infinite;}@keyframestyping-#{$i}{0%{height:0;}25%{height:100%;}100%{height:100%;content:$contentNext;}}}看看效果,有了不错的提升:当然,上面的效果其实还是有些区别的从水平打字变为垂直打字。在现有的垂直排列规则下,无法通过字符数与ch匹配得到实际的垂直高度。所以这里有一定的权衡。从实际放慢动画的角度来看,无字的出现可能并不完整。当然,在快速动画效果下几乎察觉不到。添加光影和透明度变化最后一步是增加光影和透明度变化。最好的效果就是让每一个新角色的亮度都保持在最大,而已经出现的角色亮度逐渐减弱。但是由于我们这里不能对每一个字符进行微调,只能对每一行字符进行操作,所以我们只好另辟蹊径来实现了。最后的办法就是借用另外一个伪元素来同步mask来达到最终的效果。让我们一步一步地看一下这个过程。为文字添加亮色和高光第一步是为文字添加亮色和高光,非常简单,只需要在黑色底色下选择亮色,使用text-shadow让文字发光即可。p::before{color:rgb(179,255,199);text-shadow:001px#fff,002px#fff,005pxcurrentColor,0010pxcurrentColor;}看效果,左边是白色字符,中间是改变字符颜色,还有右边是改变字体颜色并添加字体阴影效果:给文字添加一个同步遮罩接下来,在文字动画进行过程中,同步添加一个黑色到透明遮罩,尽量还原每个新字符以保持最大亮度,同时已经出现的字符亮度逐渐减弱。这个效果的示意图大致是这样的。这里我将文字层和遮罩层分开,并将背景颜色由黑色改为白色,方便理解:遮罩层的伪代码如下,使用Arrivingatanotherpseudo-elementoftheelement:p::after{content:'';background:linear-gradient(rgba(0,0,0,.9),transparent75%,transparent);background-size:100%220%;background-repeat:no-repeat;animation:mask4sinfinitelinear;}@keyframesmask{0%{background-position:0220%;}30%{background-position:00%;}100%{background-position:00%;}}嗯,最后加在一起的效果大概是这样的:通过调整@keyframesmask的一些参数,可以得到不同的字符淡入淡出效果,需要一定的调试。完整代码和效果都OK。我拆解了主要步骤,最后上传了完整的代码,应用了Pug模板引擎和SASS语法。完整的代码加起来不到100行。.g-container-for(vari=0;i<50;i++)p@importurl('https://fonts.googleapis.com/css2?family=Inconsolata:wght@200&display=swap');$str:'??????????ㄅㄉㄓㄚㄢㄦㄊㄍㄐㄔㄗㄧㄛㄟㄣㄇㄋㄎㄑㄑㄕㄘㄘㄜㄜㄠㄠㄈㄏㄡㄥabcdefghigklmnopqrstuvwxyz123456789%@#$<>^&*_+';$length:str-length($str);$n:50;$animationTime:4;$perColumnNums:25;@functionrandomChar(){$r:random($length);@returnstr-slice($str,$r,$r);}@functionrandomChars($number){$value:'';@if$number>0{@for$ifrom1through$number{$值:$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;宽度:5vh;高度: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;高度:100%;溢出:隐藏;}}@for$ifrom0through$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:001px#fff,002px#fff,005pxcurrentColor,0010pxcurrentColor;动画:打字-#{$i}$randomAnimationTinesteps(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),transparent75%,transparent);background-size:100%220%;background-repeat:no-repeat;animation:mask$randomAnimationTineinfinite#{($delay-2)*0.1s*-1}linear;z-index:2;}@keyframestyping-#{$i}{0%{height:0;}25%{height:100%;}100%{高度:100%;内容:$contentNext;}}}@keyframesmask{0%{background-position:0220%;}30%{background-position:00%;}100%{background-position:00%;}}最终效果如图题图:数字炭雨动画完整代码和演示效果可以点击这里:CodePenDemo--数字炭雨动画[3]最后的灵感来源于袁传老师的这个效果[4]CodePenDemo--Matrixdigitalrain[5],原始效果是使用JavaScript实现的。本文使用纯CSS进行演绎。本文到此结束。希望对你有所帮助:)参考文献[1]《你该知道的字体 font-family》:https://github.com/chokcoco/iCSS/issues/6[2]CodePenDemo——纯CSS实现文字输入效果:https://codepen.io/Chokcoco/pen/WXGoGB[3]CodePenDemo——数字字符雨动画:https://codepen.io/Chokcoco/pen/bGWvNme[4]元川:https://github.com/yuanchuan[5]CodePenDemo——矩阵数字雨:https://codepen.io/yuanchuan/pen/YoqWeR