今日はちょっと難しい話をしますね。作り手向けの回です。専門用語が続くので、「そういう細かいことをやっているんだな」くらいで読み飛ばしていただいて大丈夫です。普段の記事はこちら → サイトの第一印象は、最初の数秒で決まる

自社サイト yorozutech.com のトップページに、オープニング演出を入れました。マスコットの「よろずん」がテクテク歩いて登場し、中央で“起動”してロゴが立ち上がり、白いフラッシュでサイトへ切り替わる——という約8秒の演出です。
動画ファイルも、アニメーションライブラリも使っていません。CSSアニメーションと、20行ほどのJavaScriptだけで作っています。この記事では、その設計と、実際にハマった落とし穴を残しておきます。
なぜ動画ではなくCSSなのか
最初に「後光が差す映像」を動画で作って試したことがあります。結果は失敗でした。
- 圧縮でポリゴン感が出て、明るい部分が白飛びする
- 読み込みが入るぶん、再生開始がカクつく
- ファイルが重く、スマホの初回表示に響く
演出は「軽くて、どの端末でも同じように動く」ことが大前提です。結局、CSSだけで作り直すのが正解でした。グラデーションとtransformで作った光は、拡大してもにじまず、ファイルサイズはゼロです。
演出の構造
全体は1枚のオーバーレイ(#yzintro)で、ページの上にposition:fixedで重ねています。中身はこれだけです。
- ネオンの遠近フロア(
repeating-linear-gradientをrotateXで寝かせたもの) - 歩いてくるマスコット
- 起動の衝撃波リング/放射(
repeating-conic-gradient) - ワードマークとキャッチフレーズ
- 白いフラッシュ
歩く動きは「横移動」と「跳ね」を分ける
歩行は、横に進む動きと上下に跳ねる動きを別々の要素に持たせると破綻しません。同じ要素に2つのtransformアニメーションを当てると、後から始まった方が前の値を打ち消してしまうからです。
.yzi-walker{ transform:translateX(-30vw);
animation:yzi-walkx 2.05s cubic-bezier(.33,0,.4,1) .3s both }
.yzi-walker img{ transform-origin:50% 100%;
animation:yzi-hop .5s cubic-bezier(.3,0,.4,1) .3s 4 both }
@keyframes yzi-walkx{ to{ transform:translateX(0) } }
@keyframes yzi-hop{
0% { transform:translateY(0) scaleY(.96) rotate(-3deg) }
32% { transform:translateY(-24%) scaleY(1.05) rotate(3deg) }
62% { transform:translateY(0) scaleY(.9) }
100%{ transform:translateY(0) scaleY(1) rotate(-3deg) }
}
62%でscaleY(.9)に潰すのがポイントで、これだけで「着地」の質感が出ます。transform-originを足元(50% 100%)にしておくと、潰れたときに足が浮きません。
起動の光は擬似要素ではなく専用レイヤーで
衝撃波リングは円のborderをscale()で広げるだけ、放射状の光はrepeating-conic-gradientをmaskで中心を抜いて回しているだけです。どちらも画像を使っていません。
ハマった落とし穴
1. フラッシュの後に、文字がもう一度見えてしまう
最後の「ピカーッ」と光る演出で、白いフラッシュをopacity:0 → 1 → 0と戻していたところ、白が引いた瞬間に下のロゴが再び現れてから消える、という不自然な流れになっていました。
直し方はシンプルで、フラッシュは白のまま保持し、その白ごとオーバーレイをフェードアウトさせます。こうすると「白 → サイト」に素直につながります。
@keyframes yzi-flash{ from{opacity:0} to{opacity:1} } /* 戻さない */
@keyframes yzi-exit { 0%{opacity:1}
100%{ opacity:0; transform:scale(1.06); visibility:hidden } }
2. JavaScriptが無効だと、演出が消えない
オーバーレイをJavaScriptだけで除去していると、JSが動かない環境でページが永久に隠れます。これは事故です。
対策として、退場アニメーションの最終フレームでvisibility:hiddenまで到達させ、animation-fill-mode:forwardsで固定しました。JavaScriptは「DOMから片付ける」「タップでスキップする」だけの担当にしています。
3. マスコットが半分の大きさになる
高解像度の新しい素材に差し替えたら、マスコットが半分の大きさで表示されました。原因は素材そのもので、キャラクターの周囲に大きな余白が入っていたためです。背景を透過しても余白は透明なまま残るので、見た目だけが縮みます。
アルファの境界(バウンディングボックス)で切り詰めることで解決しました。素材を差し替えるときは、透過の有無だけでなく「余白が詰まっているか」まで確認したほうが安全です。
忘れてはいけない配慮
演出は、見たくない人・見られない人への配慮とセットです。
prefers-reduced-motion: reduceの環境では演出を丸ごと無効化する- 画面タップでいつでもスキップできる
- オーバーレイは
z-indexで最前面に置き、終了後はpointer-eventsを切る
@media (prefers-reduced-motion:reduce){ #yzintro{ display:none !important } }
タイミングは0.05秒単位で詰める
最終的に一番時間をかけたのは、実は見た目ではなく間(ま)でした。足音の間隔を0.5秒ぴったりに揃える、ロゴが出てから次の行が出るまでを0.65秒空ける、締めのフラッシュはマスコットが消えきった瞬間に始める——このあたりを0.05秒単位で調整しています。
演出は「何を出すか」より「いつ出すか」で印象が決まります。数値を一覧にして、前後の間隔を眺めながら詰めるのがおすすめです。
まとめ
- 動画に頼らなくても、CSSだけで“重さゼロ”の演出は作れる
transformは役割ごとに要素を分けると破綻しない- JS無効でも必ず消える設計にする(
forwards+visibility:hidden) prefers-reduced-motionとスキップ導線は必須- 素材差し替え時は余白まで確認する
実際の動きは、トップページを開けばそのまま流れます。ぜひ一度ご覧ください。