Posted at

CSSのみで動くグリッチエフェクトをデザインする


グリッチエフェクトってかっこよくない?

あのブラウン管に写ったジャギジャギチカチカした感じのことをグリッチエフェクトといいます。

不穏なイメージや怪しいイメージにピッタリのエフェクトですが

そんなエフェクトをCSSだけで実装していきます!


まずは完成品を

gifanimation.gif

これをなんとかしてCSSでデザインしてみます。

理屈は結構簡単です。


まずは土台を作る


index.html

<!DOCTYPE html>

<html>
<head>
<title>ノイズアニメーション</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="noise_box">
<div class="block">
<span>9時間9人9の扉</span>
</div>
<div class="block">
<span>9時間9人9の扉</span>
</div>
<div class="block">
<span>9時間9人9の扉</span>
</div>
<div class="block">
<span>9時間9人9の扉</span>
</div>
<div class="block">
<span>9時間9人9の扉</span>
</div>
</div>
</body>
</html>


style.css

#noise_box{

--noise_box_height:100px;

position:relative;
top:500px;
left:500px;
width:500px;
height:var(--noise_box_height);
font-size:72px;
color:#FFFFFF;
background:#000000;
}

.block{
overflow:hidden;
position:absolute;
left:0px;
width:100%;
height:100%;
}
.block>span{
display:inline-block;
position:absolute;
left:0px;
width:100%;
line-height:var(--noise_box_height);
text-align:center;
}


実行するとこんな感じになります

SnapCrab_NoName_2018-12-29_16-24-3_No-00.png

一見普通のテキストですが、実際には同じテキスト5つが重なっています。

#noise_box内の.blockposition:absoluteが掛かっているためですね。

ではこれをベースに手を加えていきます。


テキストを横に分割する


style.css

#noise_box{

--noise_box_height:100px;

position:relative;
top:500px;
left:500px;
width:500px;
height:var(--noise_box_height);
font-size:72px;
color:#FFFFFF;
background:#000000;
}

.block{
overflow:hidden;
position:absolute;
left:0px;
width:100%;
height:100%;
}
.block>span{
display:inline-block;
position:absolute;
left:0px;
width:100%;
line-height:var(--noise_box_height);
text-align:center;
}

.block:nth-child(1){
top:calc(var(--noise_box_height) * 0);
height:calc(var(--noise_box_height) * 0.3);
color:#FFFFFF;
}
.block:nth-child(1)>span{
top:calc(var(--noise_box_height) * -0);
}

.block:nth-child(2){
top:calc(var(--noise_box_height) * 0.3);
height:calc(var(--noise_box_height) * 0.1);
color:#FF0000;
}
.block:nth-child(2)>span{
top:calc(var(--noise_box_height) * -0.3);
}

.block:nth-child(3){
top:calc(var(--noise_box_height) * 0.4);
height:calc(var(--noise_box_height) * 0.2);
color:#00FF00;
}
.block:nth-child(3)>span{
top:calc(var(--noise_box_height) * -0.4);
}

.block:nth-child(4){
top:calc(var(--noise_box_height) * 0.6);
height:calc(var(--noise_box_height) * 0.1);
color:#0000FF;
}
.block:nth-child(4)>span{
top:calc(var(--noise_box_height) * -0.6);
}

.block:nth-child(5){
top:calc(var(--noise_box_height) * 0.7);
height:calc(var(--noise_box_height) * 0.3);
color:#FFFFFF;
}
.block:nth-child(5)>span{
top:calc(var(--noise_box_height) * -0.7);
}


実行するとこんな感じになります。

SnapCrab_NoName_2018-12-29_16-28-41_No-00.png

テキストが横に分割されて理解しやすいように色を付けました。

どういった仕組みかというと

5つの同じテキストの高さをそれぞれ縮めて、他の.blockの縮めた分の位置を調整して、さらに中のspanの位置を調整を調整してます。

例えば1つ目の.blockで言えば

.blockの高さを100px*0.3=30pxにして

1つ目より前の.blockの高さを考慮してtop:0pxにして

中のspanの位置をtop:0pxにします。

さらに例えば3つ目の.blockで言うなら

.blockの高さを100px*0.2=20pxにして

3つ目より前の.blockの高さ(30px+10px)を考慮してtop:40pxにして

中のspanの位置をtop:-40pxにします。


分割したそれぞれにエフェクトを掛けていく


style.css

#noise_box{

--noise_box_height:100px;

position:relative;
top:500px;
left:500px;
width:500px;
height:var(--noise_box_height);
font-size:72px;
color:#FF8800;
background:#000000;
}

.block{
overflow:hidden;
position:absolute;
left:0px;
width:100%;
height:100%;
}
.block>span{
display:inline-block;
position:absolute;
left:0px;
width:100%;
line-height:var(--noise_box_height);
text-align:center;
}
@keyframes noise_animation{
0%{left:0px;}
10%{left:0px;filter:none;}10.25%{left:30px;filter:hue-rotate(90deg) invert(70%);}10.5%{left:0px;filter:none;}
70%{left:0px;filter:none;}70.25%{left:-30px;filter:hue-rotate(270deg) invert(30%);}70.5%{left:0px;filter:none;}
100%{left:0px;}
}

.block:nth-child(1){
top:calc(var(--noise_box_height) * 0);
height:calc(var(--noise_box_height) * 0.3);
}
.block:nth-child(1)>span{
top:calc(var(--noise_box_height) * -0);
animation:noise_animation 11s linear alternate infinite;
}

.block:nth-child(2){
top:calc(var(--noise_box_height) * 0.3);
height:calc(var(--noise_box_height) * 0.1);
}
.block:nth-child(2)>span{
top:calc(var(--noise_box_height) * -0.3);
animation:noise_animation 10s linear infinite;
}

.block:nth-child(3){
top:calc(var(--noise_box_height) * 0.4);
height:calc(var(--noise_box_height) * 0.2);
}
.block:nth-child(3)>span{
top:calc(var(--noise_box_height) * -0.4);
animation:noise_animation 9s linear infinite;
}

.block:nth-child(4){
top:calc(var(--noise_box_height) * 0.6);
height:calc(var(--noise_box_height) * 0.1);
}
.block:nth-child(4)>span{
top:calc(var(--noise_box_height) * -0.6);
animation:noise_animation 11s linear reverse infinite;
}

.block:nth-child(5){
top:calc(var(--noise_box_height) * 0.7);
height:calc(var(--noise_box_height) * 0.3);
}
.block:nth-child(5)>span{
top:calc(var(--noise_box_height) * -0.7);
}


実行するとこんな感じになります。

gifanimation.gif

仕組みを解説すると

分割したそれぞれの.blockanimationで動きを付けています。

グリッチエフェクトっぽくアニメーションするために

・ズレた動きをするの%を小数点単位で指定し一瞬になるようにする。

・ズレたときに色を変えるためにfilter:hue-rotate(90deg) invert(70%);などフィルターを掛ける。

・他の.blockとアニメーションが被らないようにanimation-durationanimation-directionをバラバラに指定する。

ようにしています。

もっとリアリティを出すためにtransform:skew()なんてのも掛けても良いかもしれませんね。