🌨️
【CSS】雪を降らせるエフェクト
Twitterで偶然見つけた雪を降らせるエフェクト。
ちなみに私が作ったものはこちら↓
公式サイトに行ってみると、誰でもコピペするだけで使えるようになっています。
スクリプトの中身もminifyされているだけで、コードも比較的短かったので簡単に読むことができました。ちなみに、minifyされたコードを元に戻すためにdirtyMarkupというサイトを利用したました。
コードが短いとはいえ、そのまま貼り付けてしまうのは憚られたので、読んだコードを元に自分でも似たようなコードを書いてみます。
プログラムの概要
コードを見た方が早いかと思いますが、どのように作っているのかを言語化します。
HTML文字列の作成
- JavaScript を使用して、同じクラスを持つ多数の
i
タグ文字列を作成します。
CSSの作成
- 作成した
i
タグのクラスに対するCSS文字列を作成します。 - 乱数を使って、位置や透明度、大きさなどの値を決めます。
- CSSの
:nth-child()
を使って、作成したタグ
の数の分だけ、位置などを定義します。 -
position:fixed
に設定します。
埋め込み
-
createElement
でdiv
要素を作り、独自のidを設定する。 - 作成したdiv要素の中にHTML文字列とCSS文字列をinnerHTMLを使って入れます。
- 完成
作ってみる
参考にしたスクリプトでは、JavaScriptで全てを文字列として作成し埋め込んでいましたが、それでは分かりにくいので、HTML、CSS、JSに分けて出来るだけ分かりやすくなるように書き換えてみました。
HTML
<div id="snow-scene">
</div>
CSS
body {
background-color: black;
color:white;
}
#snow-scene {
position: fixed;
left: 0;
top: 0;
bottom: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
z-index: 9999999;
pointer-events: none;
}
.snow {
position: absolute;
width: 10px;
height: 10px;
background: white;
border-radius: 50%;
}
// JSで変更するパラメータ
.snow{
opacity: 0.5;
transform: translate(6.21vw,-10px) scale(0.51);
animation: fall-x 18s -21s linear infinite;
}
@keyframes fall-x {
30% {
transform: translate(11.40vw,30.00vh) scale(0.51);
}
100% {
transform: translate(8.80vw, 105vh) scale(0.51);
}
}
snow
クラスを二つに分けているのは、2つ目をサンプルとして残しているからです。また、keyframesはJavaScript側で値を操作できなかったので、fall-x
もサンプルとして残しているだけで使っています。
keyframesは、JavaScript側で作成して埋め込んでいます。(ここが汚い)
const rnd = (a, b, c) => Math.floor(Math.random() * (b - a + 1)) + a;
function SnowFall() {
const snow_scene = document.getElementById("snow-scene");
let keyframes = ""
for(i = 1; i < 200; i++) {
let snow = document.createElement('i');
snow.classList.add('snow');
const X = (rnd(0, 1000000) * 0.0001),
O = rnd(-100000, 100000) * 0.0001,
T = (rnd(3, 8) * 10).toFixed(2),
S = (rnd(0, 10000) * 0.0001).toFixed(2);
snow.style.animationName = `fall-${i}`;
snow.style.opacity = (rnd(1, 10000) * 0.0001).toFixed(2);
snow.style.transform = `translate(${X.toFixed(2)}vw, -10px) scale(${S})`;
snow.style.animation = `fall-${i} ${rnd(10, 30)}s -${rnd(0, 30)}s linear infinite`
keyframes += `@keyframes fall-${i}{
${T}%{
transform: translate(${(X + O).toFixed(2)}vw,${T}vh);
}
100%{
transform:translate(${(X + (O / 2)).toFixed(2)}vw,105vh);
}
}`;
snow_scene.appendChild(snow);
}
snow_scene.innerHTML += `<style>${keyframes}</style>`
}
SnowFall();
感想
自分が作ったものを他の人と比べるのはとても勉強になりました。
私が作った雪はアニメーションの切れ目がわかってしまうという欠点がありますが、個人的には自分が書いたSVGを使ったコードの方が比較的短めで好みなので、これを組み合わせてに少し改良してみようかと思います。また、このようなエフェクトを誰でも使えるようにいくつか整備してみるのも面白いかもしれません。
Discussion