🧊

CSS animationを学び、ノイズアニメーションを作ってみる

2022/06/18に公開

CSS animation を学ぶ

ポートフォリオサイトを作ろうと思った時に、せっかくならやったことのないことを学ぼうと CSS animation を勉強しています。
ただ勉強するのも、と思ったので、今回は CSS animation の簡単な紹介と、ノイズアニメーションを作ってみたいと思います。

CSS でアニメーションする方法

CSS のアニメーションは

  1. transition を使ったシンプルなアニメーション
  2. animation@keyframes を使った複雑なアニメーション

があります。

transition を使ったアニメーション

transition を使ったアニメーションはとてもシンプルです。
何か変化がある要素の CSS に対して transition を設定するだけでアニメーションが実現できます。

.content {
  /* widthが変動したらtransitionをする */
  transition: width 1s;
  height: 100px;
  width: 100px;
  background-color: white;
}

.width {
  width: 400px;
}

This is Test ボタンを押下したときに、 .content クラスのついた要素に .width クラスをつけてあげると下記のようになります。

transition には以下のプロパティが設定できます。

プロパティ名 どんなプロパティか
transition-property トランジションを適用する CSS プロパティを指定する height
transition-duration トランジションにかかる時間を指定する 1s
transition-delay トランジション開始までの待ち時間を指定する 1s
transition-timing-function トランジションの中間状態の指定 ease(徐々に速く、徐々に遅く)

transition プロパティの楽なところは、中間の状態を考えなくて良いことです。
アニメーションを作るときには最初の状態から最後の状態まで、中間の状態を意識する必要があります。
transition プロパティでは、その中間の動きを一切考える必要がないのがメリットです。
始点と終点でどのような動きになるかだけを与えてあげると、あとは中間を計算してやってくれるので、誰でも比較的なめらかな動きを表現することができます。

animation と @keyframes を使った複雑なアニメーション

transition は便利ですが、複雑な挙動を伴うアニメーションは中間の状態が指定できないので対応できないです。
どうしても複雑なアニメーションをしたい、、、!そんな時に使えるのが animation@keyframes になります。

.content2 {
  height: 100px;
  background-color: white;
  /* animation プロパティにアニメーション、 時間、 繰り返しなどを設定する */
  animation: width-animation 2s infinite;
}

@keyframes width-animation {
  0% {
    width: 100px;
  }
  100% {
    width: 400px;
  }
}

animationkeyframes を使ったアニメーションは、 @keyframes の内部で % を指定、アニメーションが実行される時間内での動きを指定できます。
上のアニメーションを下記のように指定してあげると、要素を伸び縮みさせることができるようになります。

@keyframes width-animation {
  0% {
    width: 100px;
  }
  25% {
    width: 400px;
  }
  50% {
    width: 200px;
  }
  100% {
    width: 400px;
  }
}

このように、transition よりもより複雑なアニメーションを簡単に可能にするのが animationkeyframes になります。

keyframes の実践:ノイズを作ってみる

ここまでで一旦 CSS アニメーションについてはざっと説明したので、実際に手を動かして実践してみたいと思います。
今回は文字にノイズを走らせてみます。

ノイズの実装を考える

ノイズを走らせるにあたって、どうすれば良いか考えます。
幸いなことにモニターに接続するケーブルがいい感じに接続不良を起こして画面にノイズが走っていたので、ノイズをを観察します。
ノイズを観察した結果、重要そうな要素は

  1. 画面の一部がずれているような様子であること
  2. 規則性がなく、ひたすら不規則に乱れが起き続ける

の 2 つのようでした。
この 2 つをステップを分けてアニメーションにしていきます。

第一ステップ:ずれを作る

まずは初めに挙げた 画面の一部がずれているような様子であること を実現してみます。
今回は ずれclip-path を使って表現したいと思います。

index.tsx
import type { NextPage } from 'next'
import style from '../styles/Top.module.css'

const Top: NextPage = () => {
  return (
    <div className={style.top_container}>
      <p className={style.test} data-text="TEST">TEST</p>
    </div>
  )
}

export default Top
Top.module.css
.test {
  position: relative;
  width: 400px;
  color: white;
  font-size: 100px;
}

.test::before {
  /* beforeでテキスト要素を取得する */
  content: attr(data-text);
  position: absolute;
  background-color: black;
  color: white;
  width: 400px;
  /* clip-pathで要素をくり抜く 今回はinsetで単純な四角形とする */
  clip-path: inset(55px 0 0 0);
  /* 位置をずらす */
  left: 2px;
}

簡単に説明すると

  1. content: attr();data-text に指定した表示させる文字と同様の文字を取得
  2. clip-path で上から 55px 以下からの範囲で文字を切り抜く
  3. left で文字をずらす

ということをしています。
さらにこの inset の幅を小さくしてみましょう。

Top.module.css
.test::before {
  ...
  /* bottomの位置を調節して、clip-pathで切り抜く要素を狭める */
  clip-path: inset(55px 0 56px 0);
  ...
}

少しノイズらしくなりました。ここからこれをアニメーションにしていきましょう!

第二ステップ:ずれを動かして、ノイズにする

第一ステップでのずらしを @keyframes を使うことで動的にして、ノイズっぽくします。
下記のサンプルに従って、 clip-path を動かしてみましょう。

Top.module.css
.test::before {
  ...
  animation: noise-animation 2s infinite;
}

/* アニメーション本体 */
@keyframes noise-animation {
  0% {
    clip-path: inset(93px 0 21px 0);
  }
  5% {
    clip-path: inset(91px 0 23px 0);
  }
  10% {
    clip-path: inset(89px 0 25px 0);
  }
  15% {
    clip-path: inset(93px 0 21px 0);
  }
  20% {
    clip-path: inset(58px 0 56px 0);
  }
  25% {
    clip-path: inset(56px 0 54px 0);
  }
  30% {
    clip-path: inset(60px 0 54px 0);
  }
  35% {
    clip-path: inset(56px 0 54px 0);
  }
  40% {
    clip-path: inset(93px 0 21px 0);
  }
  45% {
    clip-path: inset(91px 0 23px 0);
  }
  50% {
    clip-path: inset(89px 0 25px 0);
  }
  55% {
    clip-path: inset(93px 0 21px 0);
  }
  60% {
    clip-path: inset(55px 0 59px 0);
  }
  65% {
    clip-path: inset(25px 0 90px 0);
  }
  70% {
    clip-path: inset(28px 0 88px 0);
  }
  75% {
    clip-path: inset(32px 0 84px 0);
  }
  80% {
    clip-path: inset(35px 0 81px 0);
  }
  85% {
    clip-path: inset(93px 0 21px 0);
  }
  90% {
    clip-path: inset(89px 0 25px 0);
  }
  95% {
    clip-path: inset(82px 0 32px 0);
  }
  100% {
    clip-path: inset(87px 0 27px 0);
  }
}

ちょっと clip-path の影響か、 before 要素に border らしきものが出てしまっていますが、ノイズらしい動きになりました!
(もしどなたか border らしきものを消せるようにできるならばコメントもらえると嬉しいです、、、!)
ちなみにさらにノイズらしくするためには after の疑似要素も追加、別途 animation を起こしたり、また、 text-shadow をつけて疑似要素に色のついた影をつけるとよりノイズらしくなります。

終わりに

CSS animation は Javascript を介せずとも複雑なアニメーションを実現することができます。
まだまだ始めたばかりですが、調べれば調べるほど沼にハマるような気がしています。
皆様もぜひ CSS animation、やってみていただけると嬉しいです。

Discussion