CSSアニメーションを使って、Webブラウザに流れ星を流したい


tl;dr(Too Long, Don't Read)

  1. HTML/CSSを使って、Webブラウザに流れ星を流してみました
    1. 完全に再現はできないので、過度な期待はしないでください笑
  2. 成果物は以下の通りです
    1. https://boring-swartz-8cf676.netlify.app/
  3. ソースコードはこちらから確認できます
  4. 主に以下の4点のCSSの機能を用いて流れ星を実装しました
    1. CSS Animation/keyframesで「流れ星の動き」を表現
    2. linear-gradientを使って、「流れ星のしっぽ」を表現
    3. opacityで「流れ星が消える様」を表現
    4. transform: rotateを使って「流れる向き」を表現

はじめに

趣味で宇宙開発を行う団体「リーマンサット・プロジェクト」がお送りする新春アドベントカレンダーです。私はRSP-01という超小型人工衛星の、地上局運用システムの開発を担当しています。

今回は、Webブラウザに流れ星を流したかったので、HTML,CSSの基本的な技術を用いて流れ星を表現してみました。

流れ星とは?

流れ星を見たことがないという人は、Youtubeに動画が投稿されているので、見て頂くと良いと思います。

また「流れ星って何が流れているの?星なの?」など、流れ星が流れる仕組みを知りたい方は、以下のサイトが参考になります。

方針

  • HTML, CSS JavaScriptを使って表現する

実装

実装に関して、主に以下の4点を説明します。

  1. CSSアニメーションを使って、流れ星の動きを表現する
  2. linear-gradientを使って、流れ星のしっぽを表現する
  3. opacityを使って消える動きを表現
  4. transform: rotateを使って流れる向きを表現

1. CSSアニメーションを使って、流れ星の動きを表現する

まず、流れ星の動きを表現します。そのために、CSSアニメーションを利用します。
CSSアニメーションとは、CSSの記述だけで、HTML要素に動き(アニメーション)を持たせる機能です。

今回はCSSアニメーションの中で、CSS Animationを使ったアニメーションを利用して、流れ星の動きを表現してみます。
まずは、簡単に白い線を引くアニメーションを作ってみます。実際のコードは以下の通りです。

<div class="star"></div>
.star {
  height: 0;
  width: 2px;
  background: white;
  animation-name: shooting;
  animation-duration: 0.8s;
  animation-timing-function: linear;
}

@keyframes shooting {
  0% {
    height: 0;
  }

  100% {
    height: 80px;
  }
}

上のコードをWebに表示すると以下のようなアニメーションが実行されます。

今回のポイントとしてはCSS Animationの設定項目と、keyframesです。

CSS Animationではいろいろな設定項目があるのですが、今回はanimation-nameanimation-duration, そしてanimation-timing-functionの3つです。

  • animation-name
    • keyframesの名前を指定します。
  • animation-duration
    • 指定されたアニメーションの開始から終了までの時間
    • 今回は0.8s=0.8秒かけてアニメーションを実行します
  • animation-timing-function
    • アニメーションの進行方法
    • 今回は指定したアニメーションの各ステップを等しいスピードで進めるlinearを指定

次にkeyframesは実際のアニメーションの動きを指定します。0%が開始時のスタイル、100%が終了時のスタイルを指定することで、開始から終了までの動きを表現できます。今回はheight0px -> 80pxになるような指定をしています。

2. linear-gradientを使って、流れ星のしっぽを表現する

先ほどのCSSアニメーションで流れ星の流れを表現できました。ただ、これでは単なる白い棒が伸びているだけで、流れ星とは呼べません。
流れ星といったら、流れに沿って見えてくるしっぽの部分が必要です。

この流れ星の尻尾を表現するためにlinear-gradientを利用します。

linear-gradientとは色の指定方法の1つですが、その特徴は色を連続的に変えて濃淡を表現できる点です。このlinear-gradientを使って、流れ星の尻尾を表現すると、以下のようになります。

css
.star {
  height: 0;
  width: 2px;
-  background: white;
+  background: linear-gradient(transparent, rgb(255, 255, 255));
  animation-name: shooting;
  animation-duration: 0.8s;
  animation-timing-function: linear;
}

@keyframes shooting {
  0% {
    height: 0;
  }

  100% {
    height: 80px;
  }
}

上述のコードをWeb上で確認すると以下のように表現されます。流れ星の先から尻尾までに濃淡が表現されており、流れ星ぽく見えるかと思います。
-

linear-gradientの解説ですが、今回は2つの色(透明:transparent, 色:rgb(255, 255, 255))を指定してます。これによって、透明→白への濃淡が表現できました。

{
  background: linear-gradient(transparent, rgb(255, 255, 255));
}

3. opacityを使って消える動きを表現

だんだん流れ星っぽくなってきました。

次は、流れ星が消える表現を追加します。現状は、一瞬で消える動きになっていますが、フワッと消える動きにしてみたいと思います。

そのためにopacityを使います。opacityは透明度を表すCSSです。では、フワッと消える表現をopacityを使って表現すると以下のようになります。

.star {
  height: 0;
  width: 2px;
  background: linear-gradient(transparent, rgb(255, 255, 255));
  animation-name: shooting;
  animation-duration: 0.8s;
  animation-timing-function: linear;
}

@keyframes shooting {
  0% {
    height: 0;
+    opacity: 50%;
  }

+
+  50% {
+    height: 60px;
+    opacity: 100%;
+  }

  100% {
    height: 80px;
+    opacity: 0;
  }
}

変更した点は2つです。

1つ目はkeyframesに50%のステップを追加。そして、2つ目はopacityを使い、keyframesの50%をピークに透明度の上下を追加しました。

これにより流れ星が流れるに従って色が濃くなり、ピークを過ぎるとだんだん薄くなりながら消えていく表現ができました。

以下が、実際の表示です。

4. transform: rotateを使って流れる向きを表現

最後に、流れ星の流れる向きを変えられるようにします。

現状は上から下へしか流れません。この流れる向きをtrasnform: rotateを使って変えられるようにします。

transfrom rotateは、指定の要素の向きを回転させるCSSです。

要素の向きを回転させることで流れ星の流れる向きを変えてしまおうというのが、今回の実装の意図です。実際のコードが以下の通りです。

<div class="star-box">
  <div class="star">
</div>
+
+.star-box {
+  height: 100px;
+  width: 100px;
+  transform: rotateZ(45deg);
+}

.star {
  height: 0;
  width: 2px;
  background: linear-gradient(transparent, rgb(255, 255, 255));
  animation-name: shooting;
  animation-duration: 0.8s;
  animation-timing-function: linear;
}

今回はstar-boxという流れ星要素の上に新しく要素を追加しています。また、その要素にtransform: rotationを指定しています。

ポイントとしてはtransform: rotationを流れ星の要素(star)ではなく、一つ上の要素(star-box)に指定する点です。transform: rotationを流れ星の要素(star)に指定すると、CSSアニメーションによって自身の大きさが変化するにつれて全体の位置が動いてしまいます。先ほどは上から下へ流れるため高さしか変化しませんでしたが、向きを変化させることで横幅も変化してしまうことが位置がずれの原因です。

そのため、一つ上に縦横の長さを固定した要素(star-box)を作り、それを回転させることで、上述の位置ズレを回避しています。

上述のコードをWeb上で確認すると、以下のようになります。

完成

上述のコードで流れ星は完成です。

実際の成果物はnetlifyにデプロイしました。

実際のソースコードでは、ボタンを用意し、流れ星が流れる頻度を変えられるボタンを追加しています。また、ランダムに流れ星の表示位置を計算しています。表示位置については、流れ星が中心から同心円状に流れるように計算しています。これについては今回は説明を割愛します。

詰まった点

今回のコードは、当初はnuxt.jsで実装していました(以下、該当のリポジトリ)
- https://github.com/Ushinji/shooting_star_simulator

ただ、SSGでビルドしてnetlifyにデプロイすると、css animationがうまく機能しなかったので断念しました。

おわりに

今回はCSSアニメーションを使って流れ星をWeb上に表現する実装を説明しました。

実際の流れ星はもっと綺麗なので(笑)、流れ星に興味を持った方は、実際に流星群の時期に夜空を見上げてもらえればと思います。以下に、日本での流星群の時期の一覧が紹介されているWebサイトを記載しておきます。

最後に

明日は @ukisoft さんの「firebase storage のサイズが大きくなったのでオラったらやらかしちゃった話」です。

また、リーマンサット・プロジェクトは「普通の人が集まって宇宙開発しよう」を合言葉に活動をしている民間団体です。
興味を持たれた方は https://www.rymansat.com/join からお気軽にどうぞ。

参考文献