GODRICH
#cssアニメーション#ボタン#ローディング#トランジション#スクロール#ダッシュボード#実用ui#デザイントレンド

雪 アニメーション css 9種 — ふわふわ舞う雪から積もる雪まで

雪 アニメーション css は、キャンバスに雪の粒を描き、奥行き・風・積もりを計算で動かす冬の場面です。雪の粒はなぜ大きいほど速く、くっきり見えるのでしょうか。01番は大きさを奥行きとして読んで速さとぼかしをいっしょに決め、03番は積もった雪が崩れる傾きを守り、06番は街灯の光の円すいの中だけ雪を明るくします。

雪は落ちる点ではなく奥行きをもつ粒です — 雪 アニメーション css は大きさひとつで速さ・ぼかし・ゆれを決めるところから始まります

自動再生 · タイルを押すとその項目へ · すべて1つのzip

九つの場面は同じ雪の粒を使い、その値の読み方だけが違います。01・02 は雪がどう落ちるか、03・05・07 は触れた雪がどこにどう残るか、04・06 は雪と光がつくる質感を扱います。08 は速さをすじに変えて見通しをふさぎ、09 は前の計算をひとつの画面に重ねます。

大きい雪ほど速くくっきり見える理由

01 は雪の半径 s を S_MIN 1.1 と S_MAX 5.2 のあいだで 0〜1 の奥行き z に変えます。この z がひとつで落ちる速さ(0.6〜1.4倍)とぼかしの半径(最大 3.4px)を決めるので、いちばん大きい雪はいちばん小さい雪より約 2.3 倍速く落ちます。雪ごとに値を選ばなくても手前と奥の距離感が出ることが、この場面の要点です。

キャンバス 2D だけで動くソース

九つの場面は外部ライブラリ・WebGL・CDN を使わず、キャンバス 2D と requestAnimationFrame だけで動きます。乱数はシードを固定した生成器なので、同じ値で動かせば同じ雪が降ります。一コマの時間は DT_MAX 0.05 秒で切りつめるため、ファイルをひとつ貼るだけで確かめられます。

雪 エフェクト やり方の選び方

雪 エフェクト やり方を調べると、画像を重ねる方法から粒ごとに計算する方法まで幅広く出てきます。この記事は後者で、雪一粒ごとに位置を持たせるので、積もる高さや光の当たり方を値で変えられます。雪 エフェクト 動画のように再生するのではなく、ページを開くたびにコードが一コマずつ計算します。

となりの記事とちがう点

点が漂う飾りは css パーティクル 背景 の記事、雨が地面ではねる場面は 雨のエフェクト の記事が扱います。この記事は、雪が触れた場所に残る点がちがいます。高さの地図に積もり、ガラスをぬらし、傘の上をすべります。天気をアイコンで見せるカードは 天気ウィジェット ui の記事、同じキャンバス場面の基準は キャンバス 特殊効果 の記事にあります。

雪 アニメーション css 9種 — 大きさで奥行きを読む雪の層・突風の場に巻かれる雪・積もって崩れる雪だまり・窓ガラスに触れて溶ける雪・ふってしずまるスノードーム・街灯の光の円すいの中の雪・傘の上をすべる雪・すじに伸びる吹雪・雪の夜の屋根のヒーロー場面

01・02 は落ちる計算を変え、03〜05 と 07 は触れたあとの状態を保存します。06 は明るさだけを変えて雪の動きはそのままです。08 は同じ雪を速さの向きに伸ばし、09 は 03 の積もり・06 の明かり・01 の奥行きをいっしょに重ねます。

九つの場面を描いて測った面積・フレーム・強さ

場面 累積面積 動いたフレーム 強さの平均
01 奥行きの層の雪 46.6% 23/23 48.3
02 突風の場 41.8% 23/23 59.7
03 積もる雪だまり 27.2% 23/23 85.1
04 窓ガラスの溶ける雪 21.6% 23/23 29.4
05 スノードーム 20.5% 23/23 81.0
06 街灯の円すい 48.4% 23/23 42.0
07 傘のすべり 24.0% 23/23 57.4
08 吹雪 70.2% 23/23 46.8
09 屋根のヒーロー 27.7% 23/23 46.2

画面全体にすじと白い膜が広がる 08 が 70.2% でいちばん広く、球の中だけで雪が動く 05 が 20.5% でいちばん狭くなります。強さの平均は、二つのパネルに雪だまりが盛り上がる 03 が 85.1 で最高、ガラスの上の水気だけが変わる 04 が 29.4 で最低です。九つとも 23/23 のフレームで動いていました。

01大きさで奥行きを読む雪の層

冬のイベントページの最初の画面に敷くと、雪 240 粒が手前と奥の層に分かれて落ちます。speedK は奥行き 0〜1 を速さの倍率 0.6〜1.4 に広げ、blurOf は遠い雪ほどぼかしを大きくします。雪を大きさ順に一度だけ並べ替えておくので、近い雪が上に描かれます。

大きさで奥行きを読む雪の層
新しいタブで開く

01 · 大きさで奥行きを読む雪の層 — 計測 累積面積 46.611% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

Z_SPREADS_MAXspeedK
    function depthOf(s) { return (s - S_MIN) / (S_MAX - S_MIN); }
    // 深さから速さの倍率 — Z_SPREAD が 0.5 なら 0.6 ~ 1.4 倍、1.0 なら 0.2 ~ 1.8 倍
    function speedK(z) { return lerp(1 - 0.8 * Z_SPREAD, 1 + 0.8 * Z_SPREAD, z); }
    function blurOf(z) { return (1 - z) * BLUR * (0.5 + Z_SPREAD); }
    function fallOf(f) { return FALL * speedK(f.z); }
    function reset() {
        rng = seeded(101);
        flakes = [];
        for (let i = 0; i < FLAKES; i += 1) {
            const s = S_MIN + Math.pow(rng(), 1.7) * (S_MAX - S_MIN);
            flakes.push({ bx: rng() * (W + 60) - 30, y: rng() * (H + 20) - 10, s: s, z: depthOf(s), ph: rng() * TAU });
        }
        // 遠いものから描く — 近い雪が上にのるよう、大きさ順に一度だけ並べ替える
        flakes.sort(function (a, b) { return a.s - b.s; });
    }

02突風の場に巻かれる雪

季節限定イベントのポップアップの後ろに置くと、雪は一筋に落ちながら突風の所で巻き上がり、またしずみます。サイン三つの和の傾きを 90 度回して速さに使うため、雪は一点に集まることも広がるだけになることもなく、渦を巻きます。奥行きの浅い雪は場の値の 0.3〜1.0 の割合しか受けず、巻かれ方が小さくなります。

突風の場に巻かれる雪
新しいタブで開く

02 · 突風の場に巻かれる雪 — 計測 累積面積 41.808% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

GUSTGUST_SPEEDfieldAt
    function fieldAt(x, y, t) {
        let u = 0;
        let v = 0;
        for (const w of WAVES) {
            const c = Math.cos(x * w[0] + y * w[1] + t * w[2] + w[3]) * w[4];
            u += c * w[1];
            v -= c * w[0];
        }
        return [u * 34, v * 34];
    }
    // 突風の山 — 時間とともに強まったり弱まったりする割合(0.3 ~ 1)
    function gustAmp(t) { return 0.65 + 0.35 * Math.sin(t * 1.4); }

03積もって崩れる雪だまり

年末のあいさつページの、雪が積もる文字の棚に向いています。地面に着いた雪は列ごとの高さの地図に 3px ずつ足され、となりより REPOSE の限界を越えて高い列は、越えた分の半分を低いほうへ流します。左のパネルは傾きの限界を切った失敗版、右のパネルが限界を守った対策です。

積もって崩れる雪だまり
新しいタブで開く

03 · 積もって崩れる雪だまり — 計測 累積面積 27.164% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

REPOSEGRAINrelax
    function relax(p) {
        if (p.limit >= 1e6) {
            return;
        }
        const maxDiff = p.limit * GRAIN;
        for (let pass = 0; pass < 4; pass += 1) {
            for (let c = 0; c < COLS; c += 1) {
                for (let d = -1; d <= 1; d += 2) {
                    const n = c + d;
                    if (n < 0 || n >= COLS) {
                        continue;
                    }
                    const excess = surface(p, c) - surface(p, n) - maxDiff;
                    if (excess > 0 && p.h[c] > 0) {
                        const move = Math.min(p.h[c], excess * 0.5);
                        p.h[c] -= move;
                        p.h[n] += move;
                    }
                }
            }
        }
    }

04窓ガラスに触れて溶ける雪

カフェ紹介ページの窓辺の背景に合います。雪がガラスに触れると 4px のマスの水気が上がり、しずくがその下へ降りながらマスごとに水気を残して質量を減らします。水気は EVAP でかわくので筋は長く流れたあと消え、くもりの層は水気のある所だけ抜けて向こうの明かりが見えます。

窓ガラスに触れて溶ける雪
新しいタブで開く

04 · 窓ガラスに触れて溶ける雪 — 計測 累積面積 21.645% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

EVAPTRAIL_WETLAND_PER_S
        // 重力の向きに広がる — しずくは質量が大きいほど速く降り、通ったマスをぬらして質量を失う
        for (const d of drops) {
            if (d.wait > 0) {
                d.wait -= dt;
                continue;
            }
            const v = 14 + 70 * d.m;
            const steps = Math.max(1, Math.round(v * dt / CELL));
            for (let s = 0; s < steps; s += 1) {
                d.y += v * dt / steps;
                d.x += Math.sin(d.y * 0.09 + d.m * 9) * 0.12;
                const c = clamp(Math.floor(d.x / CELL), 0, GC - 1);
                const rr = Math.floor(d.y / CELL);
                if (rr >= 0 && rr < GR) {
                    const i = rr * GC + c;
                    water[i] = Math.min(1, Math.max(water[i], TRAIL_WET));
                    d.m -= TRAIL_COST;
                }
            }
        }

05ふってしずまるスノードーム

ギフトショップ紹介ページの飾りカードとして使います。決めた時間表(0.25 秒・3.6 秒)に、積もっていた雪が粒に戻って衝撃を受け、空気抵抗が速さを削って粒は秒速およそ 49.6px でしずみます。底の近く(FLOOR_SLACK 4px 以内)で速さが 40 を下回った粒は、PILE_ADD 1.5px ずつ底の雪だまりに戻り、球の壁では外向きの速さ成分だけを反転して RESTITUTION 0.45 だけ残します。

ふってしずまるスノードーム
新しいタブで開く

05 · ふってしずまるスノードーム — 計測 累積面積 20.46% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

GRAVITYSHAKE_ATRESTITUTION
            // 空気抵抗 — 速さに比例して削る
            const drag = Math.exp(-DRAG * dt);
            g.vx *= drag;
            g.vy *= drag;
            g.x += g.vx * dt;
            g.y += g.vy * dt;
            const dx = g.x - CX;
            const dy = g.y - CY;
            const d = Math.hypot(dx, dy);
            const lim = R - 5 - g.s;
            if (d > lim) {
                // 壁での反射 — 外向きの法線方向の速さ成分だけを反転し、RESTITUTION だけ残す
                const nx = dx / d;
                const ny = dy / d;
                const vn = g.vx * nx + g.vy * ny;
                if (vn > 0) {
                    g.vx -= (1 + RESTITUTION) * vn * nx;
                    g.vy -= (1 + RESTITUTION) * vn * ny;
                }
                g.x = CX + nx * lim;
                g.y = CY + ny * lim;
            }

06街灯の光の円すいの中の雪

ナイトモード紹介ページのヒーロー背景に似合います。雪一粒の明るさは円すいの角度の割合 × 距離による減衰 × 前方への散乱で決まり、円すいの外は AMBIENT 0.16 だけが残って暗くなります。円すいの軸はサインで左右に振れるので、明るい雪のかたまりが入れ替わり続けます。

街灯の光の円すいの中の雪
新しいタブで開く

06 · 街灯の光の円すいの中の雪 — 計測 累積面積 48.378% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

CONE_HALFLAMP_RANGEPHASE_G
    // 雪一粒の明るさ — 円すいの割合 × 距離による減衰 × (1 + 前方への散乱)、円すいの外は AMBIENT
    function brightness(f, axis) {
        const dx = f.x - LAMP_X;
        const dy = f.y - LAMP_Y;
        const d = Math.hypot(dx, dy);
        if (d < 1) {
            return 1;
        }
        let th = Math.abs(Math.atan2(dy, dx) - axis);
        if (th > Math.PI) {
            th = TAU - th;
        }
        const t = th / CONE_HALF;
        const cone = t < 1 ? Math.pow(Math.cos(t * Math.PI / 2), CONE_POWER) : 0;
        const fall = 1 / (1 + (d / LAMP_RANGE) * (d / LAMP_RANGE));
        // 前方への散乱 — 光が雪を通ってカメラ側へ向かう度合い。カメラに近い雪(z が大きい)ほど大きく、円すいの真ん中と外では 0 で、半角の半分あたりで最大になる
        const toward = clamp(f.z * 1.2 - 0.2, 0, 1) * Math.sin(Math.min(1, t) * Math.PI);
        const cosA = clamp(toward, 0, 1);
        const hg = (1 - PHASE_G * PHASE_G) / Math.pow(1 + PHASE_G * PHASE_G - 2 * PHASE_G * cosA, 1.5);
        const scat = SCATTER * hg * 0.14;
        return clamp(AMBIENT + cone * fall * (0.9 + scat), 0, 1.4);
    }

07傘の上をすべる雪

天気通知サービスの雪の日のカードに置きます。楕円の傘の面の法線を求め、上から降りて面を越えた雪だけを触れさせ、接線の速さの 0.6 倍だけを残して縁までずらします。横から入った雪は傘の下を通り抜けるので、傘の下の影の楕円は雪を止めません。地面に着いた雪は ground の配列に land() で 0.7 ずつ足され、CAP の 16px まで積もります。

傘の上をすべる雪
新しいタブで開く

07 · 傘の上をすべる雪 — 計測 累積面積 23.972% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

SLIDE_GFRICTIONnormalAt
                if (Math.abs(f.x - CX) < A) {
                    const sy = surfY(f.x);
                    // 上から降りて面を越えた雪だけが触れる — 横から入った雪は傘の下を通り抜ける
                    if (prevY <= sy && f.y >= sy) {
                        const n = normalAt(f.x, sy);
                        f.dir = f.x >= CX ? 1 : -1;
                        // 接線 — 下り坂の側(下へ向かう側)にとる
                        const tx = f.dir * -n[1];
                        const ty = f.dir * n[0];
                        // 法線の成分は消し、接線の成分の 0.6 だけを速さとして残す
                        f.speed = Math.max(0, (f.vx + wind) * tx + f.vy * ty) * 0.6;
                        f.y = sy;
                        f.mode = 1;
                    }
                }

08すじに伸びる吹雪

ウィンタースポーツ紹介ページの読み込み場面に使います。雪の速さの向きに、速さ × EXPOSURE の長さの線分を引いて雪をすじに伸ばし、遠い雪は空の色に混ぜて見通しを減らします。左のパネルは隠れたタブのあとの長い一コマをそのまま使った失敗版で、右のパネルが DT_MAX で切りつめた対策です。

すじに伸びる吹雪
新しいタブで開く

08 · すじに伸びる吹雪 — 計測 累積面積 70.178% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

EXPOSUREHIDDEN_SDT_MAX
    function drawStorm(s, ox) {
        ctx.save();
        ctx.beginPath();
        ctx.rect(ox, 0, PANEL_W, H);
        ctx.clip();
        ctx.translate(ox, 0);
        const g = gustAt(sceneT);
        const sky = mix(SKY_TOP, SKY_BOT, 0.5);
        for (const f of s.fl) {
            const vx = (WIND * g + 40) * (0.4 + f.z);
            const vy = FALL * (0.3 + 0.9 * f.z);
            const len = EXPOSURE;
            const c = mix(SNOW, sky, (1 - f.z) * FOG);
            seg(f.x - vx * len, f.y - vy * len, f.x, f.y, 0.7 + f.z * 1.9, c, 0.3 + 0.65 * f.z);
        }
        // 真っ白にふさがる — 突風が強いほど濃い膜
        ctx.fillStyle = rgba(SNOW, 0.34 * g * g);
        ctx.fillRect(0, 0, PANEL_W, H);
        ctx.restore();
    }

09雪の夜の屋根のヒーロー場面

年末キャンペーンサイトのヒーローに使います。屋根の形の高さの地図には近い雪(z 0.45 以上)だけが積もり、一粒を三つの列に 0.5・0.25・0.25 で分けて足すので、屋根の線がなめらかに厚くなります。街灯の円すいの中の雪だけが明るく、遠い雪は家の後ろを通って地面から上へ戻ります。

雪の夜の屋根のヒーロー場面
新しいタブで開く

09 · 雪の夜の屋根のヒーロー場面 — 計測 累積面積 27.677% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

ROOF_SLOPEREPOSECONE_HALF
            // 近い雪(z ≥ 0.45)だけが屋根と地面に触れて積もる。遠い雪は家の後ろを通り、地面から上へ戻る
            if (f.z >= 0.45) {
                const c = clamp(Math.floor(f.x / GRAIN), 0, COLS - 1);
                if (f.y >= topOf(c)) {
                    h[c] += ADD * 0.5;
                    if (c > 0) {
                        h[c - 1] += ADD * 0.25;
                    }
                    if (c < COLS - 1) {
                        h[c + 1] += ADD * 0.25;
                    }
                    f.y = -4 - rng() * 20;
                    f.x = rng() * (W + 40) - 20;
                }
            }

雪が積もる場面を作るとき、どこにどれだけ雪を足せば自然に見えるのでしょうか?

雪はどこにも同じ量で積もるわけではありません。03 は雪の 65% を三本の筋の列(17・40・64)の近くに落とし、残りを画面全体にまき、筋の下は厚く、あいだは薄い積もり方をつくります。

文字の棚の上に積むとき

文字の上面のように高さの違う棚を BASE に置くと、雪は棚の上の表面(棚 + 積もった雪)で止まります。03 の棚は 18px・36px・12px の三つのかたまりで、雪は各かたまりの上面から積もり始めます。年末のあいさつページでは、この棚を見出し文字の上面の高さに置き換えて使えます。

屋根に積むとき

09 は近い雪だけを積もらせ、遠い雪は家の後ろを通して地面から上へ戻します。煙突のように地面の高さが 6px を超えて急に変わる所は壁と見なして流さないので、雪が煙突のわきに積もって線が折れます。積もる速さを ADD 4 にした 7 秒の演出の終わりには、屋根の線が厚くなっています。

ガラスや傘のように積もらない面では

04 は雪が積もらず溶けた水気で、07 は傘の面をすべる動きで雪の量を表します。同じ雪でも触れる面の性質が違えば残るものが変わる点が、雪の場面の説得力になります。

高さの地図で雪を積み、傾きを越えたら横へ流し、風でゆらします — 雪一粒が雪だまりになるまでの順番です

雪一粒が雪だまりになる道は四段階です。地面に触れた雪を消さず高さの地図に足し、限界を越えた差を横へ移し、風でゆらし、遠いものから描きます。

段階 すること 使う名前 使う場面
1 足す 触れた雪を列の高さに ADD だけ足し、雪は上から降り直す surface・stepPanel 03・07・09
2 流す となりより限界を越えて高ければ、越えた分の半分を低いほうへ relax 03・09
3 ゆらす サインの和の場、または矢印キーの値を雪の速さに足す fieldAt・WIND_STEP 01・02・05・08
4 描く 大きさ順に並べ、遠い雪から描く flakes.sort 01・02

限界を越えた差だけを移す理由

03 は許す高さの差を REPOSE × GRAIN に置きます。1 × 3 なので、となりの列より 3px を越えて高い列だけが崩れ、列の幅が 3px なので傾きは 45 度です。限界以下の差には触れないため、雪だまりはなだらかな丘の形に固まります。

一度に移さず四回くり返す理由

ひとつの列が崩れて低いとなりを持ち上げると、そのとなりがまた限界を越えることがあります。03 は一歩のあいだに relax の中を 4 回、09 は 3 回回して、崩れが数列先まで広がるようにします。回数を増やすほど雪だまりはなめらかになりますが、列の数だけ計算も増えます。

遠い雪から先に描く理由

01・02 は雪を大きさ順に一度だけ並べ替え、その順に描きます。小さい雪が遠い雪なので、大きい雪が上にのって隠す見た目が自然になり、毎フレーム並べ替えないので費用も一度だけです。

雪が壊れるのは、画面の下で一度に消えてぷつりと切れる雪・積もった雪が塔のように立ってしまう山・隠れたタブのあとで一気にどっと降る雪です

地面で消すと雪が切れる

雪が画面の下へ出たら消す方式では、ある瞬間に一度にすべての雪が消えて、上から補充されるまで間があきます。03 は触れた雪を高さの地図に足してから、その雪を上から降り直させるので、雪の数が途切れず続きます。

    function stepPanel(p, dt) {
        const wind = userWind() * 30;
        for (const f of p.fl) {
            f.y += f.v * dt;
            f.x += wind * dt;
            const c = clamp(Math.floor(f.x / GRAIN), 0, COLS - 1);
            if (f.y >= GROUND_Y - surface(p, c)) {
                // 地面に触れた雪は消えず、高さの地図に足されてから上で降り直す
                p.h[c] += ADD;
                respawn(p, f);
            }
        }
        relax(p);
    }

雪だまりが塔のように立つ版

03 の左のパネルは limit を 1e9 にして relax がすぐ戻る失敗版です。雪は三本の筋の列にだけ積もるので、その列がとなりと関係なく伸びて塔になります。右のパネルは同じ雪を REPOSE 1 で流し、なだらかな丘になります。

隠れたタブのあとにどっと降る雪

08 の左のパネルは、時間表(0.3・1.6・2.9・4.2 秒)ごとに、隠れたタブから戻った 1.3 秒を一歩で使います。雪が生まれる数は RATE × dt に比例するので、190 × 1.3 でおよそ 247 粒が上から一度に降り、DT_MAX で 0.05 秒に切りつめた右のパネルには約 10 粒しか生まれません。

    function update(dt) {
        if (hiddenSeen < HIDDEN_AT.length && sceneT >= HIDDEN_AT[hiddenSeen]) {
            hiddenSeen += 1;
            // 左は長い一コマをそのまま受け取り、右は DT_MAX で切りつめた分だけ受け取る
            stepStorm(storms[0], HIDDEN_S);
            stepStorm(storms[1], Math.min(HIDDEN_S, DT_MAX));
            return;
        }
        for (const s of storms) {
            stepStorm(s, dt);
        }
    }

実際にタブが隠れると九つの場面が使うループは止まり、戻ったときは lastTs を −1 に戻して、隠れていた時間が最初の一コマに乗らないようにします。それでも長いフレームが入ったときに備えて DT_MAX をもう一度かけます。圧縮ファイルはパスワード egxx7s4z で開き、03 のフォルダと 08 のフォルダの index.html を一時停止ボタンで止めておくと、壊れた版と直した版が分かれる場所を目で確かめられます。

突風を強くすると雪はどれだけ巻かれるのでしょうか — 突風の強さ・奥行きの幅・積もる速さを変えて比べます

名前 変えた値 感じ
突風を強く 02 GUST 0.6 → 1.5 雪に足す場の速さの係数が 0.6×200=120 から 1.5×200=300px/秒の 2.5 倍になり、より大きな円で巻き上がって一筋の落下が早くほどけます
傾きの限界を急に 03 REPOSE 1 → 3 となりの列とのあいだで許す高さの差が 3px から 9px に増え、傾きが 45 度から約 72 度に急になって、雪だまりがとがって高く立ち、崩れが少なくなります
奥行きの幅を広く 01 Z_SPREAD 0.5 → 1.0 速さの倍率が 0.6〜1.4 倍から 0.2〜1.8 倍に開き、いちばん奥の雪のぼかしの半径が 3.4px から 5.1px に広がって、手前と奥の距離感が深くなります

値を変える前に見ること

02 の GUST は速さの係数であって長さではありません。1.5 に上げると場の速さは 300px/秒まで届きますが、突風の山の割合(0.3〜1.0)と奥行きの割合(0.3〜1.0)がそのままかかるので、実際の巻かれ方はそれより小さくなります。REPOSE を 3 に上げると 03 の右のパネルが左の失敗版に近づくため、二つを並べて比べる必要があります。

矢印キーでも風を変えられます — いまの降り方を読み上げる文と、動きを減らす設定で静まる雪のアクセシビリティです

手のかわりに矢印キー

九つの場面の舞台の箱はフォーカスを受け取り、左右の矢印キーを押すたびに風が WIND_STEP 0.25 ずつ −1〜1 のあいだで変わり、横にドラッグしても同じ風が入ります。Enter と Space は一時停止を押し、人が最初に触れると自動の演出の風は手を離れ、状態の行は aria-live の polite で知らせます。状態の行は 03 なら「限界なしの高さ・限界 1 の高さ」のように、いまの降り方を文で読み上げます。

動きを減らす設定では雪の積もった風景が一枚

prefers-reduced-motion: reduce のときはループを止め、REST_STEPS だけ計算した止まった場面を一枚だけ描きます。落下・突風・積もりは動かず、すでに雪が降って積もった姿だけが残り、ページを開いたまま設定を変えても change のリスナーが読み直して場面を切り替えます。この設定を読む分岐は消さずに、いっしょにコピーしてください。仕様は MDN の prefers-reduced-motion にあります。

雪 アニメーション css のよくある質問 — CSSだけで作る方法・スマホでの負荷・背景として敷く方法

雪 エフェクト 無料で試すだけなら、CSSだけでも同じ場面を作れますか

01 のように大きさ別の落下だけなら css アニメーションでもできますが、この記事の場面は雪ごとに位置を保存して計算する必要があります。積もる高さの地図、傘の上のすべり、街灯の明るさはフレームごとに値を読んで描き直す方式なので、キャンバスと js が向いています。

スマホでは雪を何粒まで置けますか

場面ごとの FLAKES の定数が雪の数で、01 は 240、06 は 300 です。キャンバスの内側は 480×300 に固定し、devicePixelRatio も 2 までしか使わないので、画面が大きくなっても計算量は変わりません。それでも重いときは、FLAKES を半分に減らすところから試してください。

ページの背景として敷いてもいいですか

01・06・09 のような飾りの場面はヒーローの背景に向き、タブが隠れるとループが止まります。文字を読ませる区間では FLAKES を減らすか、雪の上に半透明の板を一枚置いて、文字のコントラストを守るほうがよいです。

解凍パスワードを入力してください

パスワードはこの記事の本文の中にあります。読み進めると出てきます。