首发于编码花
亮瞎你的氪金眼-CSS+SVG实现霓虹灯动画

亮瞎你的氪金眼-CSS+SVG实现霓虹灯动画

往事的前篇的内容见这里

一、往事3

我的非常规操作让被拉进来的姑娘有些慌张,她清了清嗓子,用柔美却略带慌张的声音说道:“靓仔,这是你叫的服务,一共是24元。”我听后一愣,很快就反应过来,用我程序员的逻辑思维发现了这句话的两个破绽:1、还没提供服务呢,怎么就收钱;2、这服务也太便宜了,难道东莞是以价廉物美取胜吗?我沉着冷静的说到:“我还没感受到服务啊,难道看我的霓虹灯算提供服务?我的霓虹灯这么辣眼睛吗?”“不是你叫的艇仔粥和冰可乐吗?”“没有啊”“你这是404房吗”“不是哦,难怪会走错,不怪你,姑娘,404是很难找到正确地址的...我们程序员都懂的"

-------------------------强行的分割线又来了---------------------------

二、搞下“瑰”

我们先从简单的svg动画开始,因为这个动画在之前搞云的动画时用过,我就不多说了,直接上代码:

<text id="textbid" text-anchor="middle" x="62%" y="60%" fill-opacity="1" rotate="40" class="textb-front"><animate attributeName="rotate" id="first" begin="0s;second.end" from="130" to="150" dur="1s"></animate>
            <animate attributeName="rotate" id="second" begin="first.end" from="150" to="130" dur="1s"></animate>
        </text>

其实就是控制”瑰“的旋转角度(rotate),造成一个晃来晃去的感觉,最终效果是这样的

请忽略后面的背景,后面会讲到,先看这个瑰字

但以为对霓虹灯多年的观察,一般这种脱离的灯都会伴随接触不良的问题,而且这种黑漆漆的谁看的见,我要让每个字都要有高光时刻

.textb-front {
            font-family: YouYuan;
            font-size: 64px;
            font-weight: normal;
            text-transform: uppercase;
            stroke: #340547;
            stroke-width: 1px;
            stroke-dasharray: 180 280;
            animation: grow 2s infinite;
        }

 @keyframes grow {
            50% {
                stroke: #f4f2f5;
                stroke-width: 2px;
                text-shadow: 0px 0px 5px #adabad;
            }
 }

知识点啊(敲黑板)

1、@keyframes 顾名思义,关键帧。在animation需要有重要变化的时候,就要设置关键帧来配置好属性,这样animation才知道到什么时候改怎么变化,50%这个就是说在animation运行到50%的时候要变化的内容。

2、animation,css动画的两兄弟之一,另外一个是transition(过渡)。animation强调流程与控制,对元素的一个或多个属性的变化进行控制,可以有多个关键帧(animation 和@ keyframes结合使用)。

3、grow 2s infinite 我们这次animation里面的三个参数,grow就是指animation用到的@keyframes的名字(animation-name),和 @keyframes grow {...}对应;2s是参数animation-duration,表示这个animation需要运行的时长;infinite是参数animation-iteration-count的值,这个参数是设置动画播放的次数,我们这边是无限循环,所以用infinite;

具体关于animation的了解,可以自行查阅这里,最后看到的效果如下:

只闪白光,可见彩色灯坏了

三、采个花

上次做静态霓虹灯的时候除了“瑰”字,花也做了残缺化的处理,残缺证明电路还是有问题,所以动画化也不能放过啊

@keyframes flicker {
            0% {
                opacity: 1;
            }

            3% {
                opacity: 0.4;
            }

            6% {
                opacity: 1;
            }

            7% {
                opacity: 0.4;
            }

            8% {
                opacity: 1;
            }

            9% {
                opacity: 0.4;
            }

            10% {
                opacity: 1;
            }

            89% {
                opacity: 1;
            }

            90% {
                opacity: 0.4;
            }

            100% {
                opacity: 0.4;
            }
        }

这次 @keyframes 设置了更多的关键帧环节,然后把它用到了花(svg)的两个path的class里面

.svg-font1 {
            fill: none;
            stroke: red;
            stroke-width: 10;
            stroke-dasharray: 880 330;
            animation: flicker 5s infinite 3s step-end;
        }
.svg-font5 {
            fill: none;
            stroke: rgb(7, 252, 117);
            stroke-width: 10;
            animation: flicker 6s infinite step-end;
        }

<path class="svg-font1"...
<path class="svg-font5"...

这次我们看到了animation更多的参数:

1、3s,这个是animation-delay参数的值,表示动画开始的时间,两个动画的时间,我一个设置了3秒,一个没有设置,这样可以让动画错开,显的真实。

2、step-end,这个比较复杂,有大佬的文章在,我就不多言了。请移步学习

最后看到的效果是这样的:


四、弄下框

框我希望实现的是能够体现视觉上向前滚动的效果,用的仍然是animation和keyframes的组合,看代码:

.rect-front {
            animation: rectchange 6s infinite step-end;
 }
@keyframes rectchange {
            0% {
                stroke: #c0f015;
                stroke-width: 2;
                stroke-dasharray: 40 10;
                stroke-dashoffset:0%;
            }
            25% {
                stroke: #ff66ff;
                stroke-width: 2;
                stroke-dasharray: 40 10;
                stroke-dashoffset:25%;
            }
            50% {
                stroke: #00EE00;
                stroke-width: 2;
                stroke-dasharray: 40 10;
                stroke-dashoffset:50%;
            }
            75% {
                stroke: #3358ff;
                stroke-width: 2;
                stroke-dasharray: 40 10;
                stroke-dashoffset:75%;
            }
            100% {
                stroke: #c0f015;
                stroke-width: 2;
                stroke-dasharray: 40 10;
                stroke-dashoffset:100%;
            }

        }

<rect id="rectid" x="12%" y="41%" rx="30" ry="30" width="340" height="90" fill-opacity="0" class="rect-front" />

这里唯一的新东西是stroke-dashoffset,作用是相对于绘制的起点偏移的量,正值(向右或者顺时针偏移),负值(向左或者逆时针),和stroke-dasharray配合在一起,通过keyframes设置不同的偏移量,就能达到线框在不停走动的效果了。

五、弄下字

字的动画其实是使用stroke的描边,代码如下:

.texta-front {
            font-family: YouYuan;
            font-size: 64px;
            font-weight: normal;
            text-transform: uppercase;
            fill-opacity: 0.3;
            stroke-width: 2px;
            stroke-dasharray: 90 310;
            animation: text-stroke 6s infinite linear;
        }
.text-1 {
            stroke: #3498db;
            text-shadow: 0 0 5px #3498db;
            animation-delay: -1.5s;
        }

        .text-2 {
            stroke: #f39c12;
            text-shadow: 0 0 5px #f39c12;
            animation-delay: -3s;
        }

        .text-3 {
            stroke: #e74c3c;
            text-shadow: 0 0 5px #e74c3c;
            animation-delay: -4.5s;
        }

        .text-4 {
            stroke: #9b59b6;
            text-shadow: 0 0 5px #9b59b6;
            animation-delay: -6s;
        }

        @keyframes text-stroke {
            100% {
                stroke-dashoffset: 1500;
            }
        }
......
<svg>
<text id="textaid" text-anchor="middle" x="35%" y="60%" fill-opacity="1" class="texta-front text-1">
            巴黎の玫
        </text>
        <text id="textaid" text-anchor="middle" x="35%" y="60%" fill-opacity="1" class="texta-front text-2">
            巴黎の玫
        </text>
        <text id="textaid" text-anchor="middle" x="35%" y="60%" fill-opacity="1" class="texta-front text-3">
            巴黎の玫
        </text>
        <text id="textaid" text-anchor="middle" x="35%" y="60%" fill-opacity="1" class="texta-front text-4">
            巴黎の玫
        </text>
</svg>

再说知识点(黑板已敲烂):

1、每个svg里面的text代表一种颜色,有多少个同样字的text就有多少种颜色动态描边,颜色设置在text-1(2,3,4)里面

2、animation-delay的意思上面提到过(还记得吗),是延迟动画开始时间,这样可以让不同颜色的描边动画错开,看起来就像不同的颜色在各自描边了

3、stroke-dashoffset: 1500; 这个上面刚刚讲过(你肯定记得),是用来设置偏移量的,这里就是设置描边的整个长度,因为动画从开始到结束,就是从0走到偏移量数值终点的过程。因为动画的时长是确定的,所以这个数字有个有意思的作用,时间相同,路径越长,那么过程中动画播放的速度就会越快,所以这个数字越大,描边的速度看起来就越快,大家可以试下。

最终的效果是这样的:


到此为止,上一章的内容全部都动画化了,大家都散了吧。

--------------------------------------散场字幕分割线-----------------------------

------------------------------------剧务:我------------------------------------

-------------------------------------售票:我(欢迎打赏)-------------------------

-------------------------------------剧本:我-----------------------------------

------------------------------------扫地:我------------------------------------

------------------------------------杂事:我------------------------------------

------------------------------------本剧终--------------------------------------


六、埃菲尔铁塔

留下来的都是喜欢漫威电影的同学,知道字幕完了还有彩蛋。巴黎的玫瑰,只有一朵玫瑰,谁知道这是哪的玫瑰,万一是东莞的呢,为了看起来更贴近巴黎,我决定再加一个埃菲尔铁塔。

我先从Iconfont-阿里巴巴矢量图标库获取一个埃菲尔铁塔的svg文件。

选它是因为它是线条型,符合霓虹灯特性

然后我用工具把它一份两半,分成上下两个部分,方便和之前的霓虹灯招牌融合(此段没有技术含量,完全是一个艺术家在考虑创作,请大家瞻仰,谢谢)

铁塔上半部分,调了颜色和线条宽度
铁塔下半部分,中间部分裁掉了

然后要开始用到svg的filter

<svg>
<filter id="glow">
            <feGaussianBlur id="glowBlur" stdDeviation="1" result="coloredBlur" />
            <feMerge>
                <feMergeNode in="coloredBlur" />
                <feMergeNode in="SourceGraphic" />
            </feMerge>
        </filter>
        <filter id="shock2">
            <feTurbulence type="fractalNoise" baseFrequency="0.2" numOctaves="1" seed="2" result="noise" id="noise">
                <animate attributeType="XML" attributeName="seed" from="2" to="120" dur="10s"
                    repeatCount="indefinite" />
            </feTurbulence>
            <feMorphology id="morph3" in="SourceGraphic" operator="dilate" radius="1" result="morph1" />
            <feMorphology id="morph4" in="morph1" operator="dilate" radius="1" result="morph2" />
            <feComposite operator="out" in="morph2" in2="morph1" result="strokeText" />
            <feDisplacementMap xChannelSelector="R" yChannelSelector="G" in="strokeText" in2="noise"
                result="displacementMap" color-interpolation-filters="sRGB" scale="10" />
            <feGaussianBlur stdDeviation="5" result="coloredBlur" />
            <feMerge>
                <feMergeNode in="coloredBlur" />
                <feMergeNode in="displacementMap" />
            </feMerge>
        </filter>
</svg>

具体的filterd组合怎么用,in,out怎么弄,我就不详述了,因为这是艺术(呸,就是调参数的体力活)。大家有能力可以去油管看这个视频,是讲filter的,翻这里

然后用一个新的做法把filter关联到svg的图像去

<use xlink:href="#tietaupid" id="textShock" x="2" y="2" filter="url(#shock2)" stroke="0" stroke-width="3"
            fill="#FFFF00" />
        <use xlink:href="#tietaupid" id="textFill" x="0" y="0" fill="white" />
        <use xlink:href="#tietaupid" id="textGlow" x="0" y="0" filter="url(#glow)" stroke="#f90" stroke-width="0.1"
            fill="transparent" />

        <use xlink:href="#tietadownid" id="textShock" x="2" y="2" filter="url(#shock2)" stroke="0" stroke-width="3"
            fill="#FFFF00" />
        <use xlink:href="#tietadownid" id="textFill" x="0" y="0" fill="white" />
        <use xlink:href="#tietadownid" id="textGlow" x="0" y="0" filter="url(#glow)" stroke="#f90" stroke-width="0.1"
            fill="transparent" />

use元素是SVG中非常强大,非常重要的一个元素,尤其在Web开发中,为何?

两点:

  1. 可重复调用;
  2. 跨SVG调用;

这里用到的就是可重复调用,我们通过use,把多种的filter叠加到svg图像里面。filter里面再使用animation,就达到了效果。

请忽略中间的部分

七、往事4

“我看的是04房啊”,姑娘疑惑的看着我,觉得我对房号似乎有特别的理解。“我这边是404的楼上,504”,我接着说:“所以服务错误很正常,这属于服务内部错误,我的问题”。我又露出了特别的微笑。“那么,对不起,我去404了。”“不要急嘛,看一下我能动的霓虹灯,这次,可高级了"

窗外,霓虹灯闪烁的更频繁了....

源码请看这里

大家如果想线上看效果,也可以访问codepen

发布于 2019-07-18 20:56