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

CSS アニメーション サンプル 9選 — 洗濯機・家・車を図形で動かす

css アニメーション サンプルとして、洗濯機・家・車などの身の回りの物を、画像を一枚も使わずに色付きの箱いくつかで描いて動かす作り方を9つまとめました。どれも純粋な CSS の図形だけで、下のグリッドの中で今動いています。

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

順番は人気順ではなく、物が1つ描けて動くまでに必要な材料の順です。まず丸い窓が機械の顔になり(01)、屋根と煙突で家が1軒立ち(02)、タイヤとライトで車が近づき(03)、文字の上を横切る影でキャラクターが生まれ(04)、機械の中の風景で画面に奥行きが出て(05)、太陽とグリッドで舞台が整い(06・07・08)、最後にトランク鞄1つがまるごと1つの世界になって締めます(09)。css イラスト アニメーションは専用ソフトなしで角丸と clip-path だけで成立し、9つとも舞台の中の四角・円・三角形の部品なので外部ファイルは0個です。同じ物を軸にした隣の記事として、窓の中の風景から始めた CSS シーン アニメーション と、キャンバスで似た舞台を描く キャンバス シーン エフェクト があります。

01洗濯機 ドラム回転

正面から見た洗濯機をクリーム色の本体・丸い扉・操作パネルで組み立て、扉の中の水と靴下がひとかたまりで回る、家電紹介画面向けの部品です。

洗濯機 ドラム回転
新しいタブで開く

01 · 洗濯機 ドラム回転 — 計測 累積面積 3.349% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

rotateanimation-play-statescaleY

ドラムは1グループにまとめて1回転

.ws__drum {
  position: absolute; inset: 0;
  animation-name: wsSpin; animation-duration: $duration;
  animation-timing-function: linear; animation-iteration-count: infinite;
}
.ws.is-pause .ws__drum { animation-play-state: paused; }

@keyframes wsSpin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
@keyframes wsBlink {
  0%, 42% { transform: scaleY(1); }
  46%, 50% { transform: scaleY(.1); }
  54%, 100% { transform: scaleY(1); }
}

水2枚と靴下・シャツを .ws__drum の1グループに入れたので回転は宣言1つで済み、停止はアニメーションを消さず animation-play-state で一時停止させます。猫はグループの外に置いて2秒ループの46%地点で1回だけ瞬きし、ボタンを押すとドラムの計算値が running から paused へ、パネルのランプは1から0.25へ変わります。

02家 — 窓の灯りと煙突の煙

ストライプの屋根と煙突のある家がスイッチ1つで夕暮れに変わる、不動産・ホームサービスのオンボーディング向け部品です。

家 — 窓の灯りと煙突の煙
新しいタブで開く

02 · 家 — 窓の灯りと煙突の煙 — 計測 累積面積 22.172% · 動いたフレーム 22/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

repeating-linear-gradientanimation-delaytransition

昼と夜は1枚の重ねの opacity

.hs__skynight {
  position: absolute; inset: 0; opacity: 0;
  background: linear-gradient(180deg, $night-top 0%, $night-bottom 100%);
  animation-name: hsCycle; animation-duration: $dur-loop;
  animation-timing-function: ease-in-out; animation-iteration-count: infinite;
}
.hs.is-night .hs__win {
  background: $stage-yellow;
  box-shadow: 0 0 12px rgba(255, 210, 63, .8);
}
@keyframes hsCycle {
  0%, 30% { opacity: 0; }
  52%, 78% { opacity: 1; }
  90%, 100% { opacity: 0; }
}

夜空と星・月を .hs__skynight の重ね1枚にまとめ、opacity だけで載せたり下ろしたりするので、人がスイッチを押すときは transition で、グリッドのプレビューでは同じキーフレームで回ります。スイッチを切ると窓ガラスが rgb(255, 210, 63) に灯って12px の光がにじみ、煙の3粒は 660ms 間隔の animation-delay でずれて立ち上り、屋根のストライプは画像ではなく繰り返しグラデーションの線です。

03近づく車と路面

夕暮れの道に真正面から突っ込んでくる車を、ボディ・ヘッドライト・流れる路面標示で組み立てた、自動車・配達サービスのランディング向け部品です。

近づく車と路面
新しいタブで開く

03 · 近づく車と路面 — 計測 累積面積 3.342% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

scalebox-shadowsteps(1, end)

路面標示は2組をつないで下へ流す

.ca__marks {
  position: absolute; left: 50%; top: -72px; width: 8px; height: 144px;
  margin-left: -4px;
  animation-name: caFlow; animation-duration: $duration;
  animation-timing-function: linear; animation-iteration-count: infinite;
}
// 間隔は margin-bottom — 無限トラックに gap は使わない
.ca__dash {
  display: block; width: 8px; height: 12px; margin-bottom: 12px;
  border-radius: $r-xs; background: rgba(255, 247, 230, .75);
}
@keyframes caFlow {
  from { transform: translateY(0); }
  to { transform: translateY(72px); }
}

車線の標示6つを 144px のトラックに 24px 間隔で植え、72px(周期3つ分)だけ下げると終わり姿勢が開始姿勢とぴったり重なって途切れません。近づいてくる感じは車グループの scale の往復が担い、ウインカーは steps(1, end) のカットで点滅し、ハイビームを点けると光の計算値が matrix(1.7, 0, 0, 1.7, 0, 0) まで膨らみます。この切替が最初は見えなかった理由は落とし穴の節で説明します。

04カラスが横切るワードマーク

カラフルなグラデーション文字の上を黒いカラスが歩いていく、ブランドワードマーク・404ページ向けの部品です。

カラスが横切るワードマーク
新しいタブで開く

04 · カラスが横切るワードマーク — 計測 累積面積 6.609% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

background-clip: texttranslateXanimation-delay

文字は背景を切り抜き、歩みは脚の回転

.cr__word {
  font-weight: 900; font-size: 76px; line-height: 1; letter-spacing: 2px;
  background: linear-gradient(92deg, $grad-a 0%, $grad-b 48%, $grad-c 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.cr__leg {
  transform-origin: top center;
  animation-name: crStep; animation-duration: 250ms;
  animation-timing-function: linear; animation-iteration-count: infinite;
}
@keyframes crWalk {
  from { transform: translateX(0); }
  to { transform: translateX(400px); }
}

グラデーションは background-clip: text で文字の形だけを残し、カラスは胴体の楕円・くちばしの三角形・脚の棒の3部品です。横断は2秒で 400px、脚は 250ms 周期で ±14度ずつ逆位相に振れて歩みになり、カラスを押すと羽が1枚 rotate(140deg) で回りながら 34px 落ちてその場に残ります。左の羽3枚は 300ms 間隔の時差で揺れています。

05サーモスタットの風景窓

丸いスマートサーモスタットの上部窓に山から昇る太陽と、それが映る湖を入れ、モードアイコンが太陽の高さ・ダイヤル・温度を同時に変える、スマートホーム製品詳細向けの部品です。

サーモスタットの風景窓
新しいタブで開く

05 · サーモスタットの風景窓 — 計測 累積面積 0.536% · 動いたフレーム 19/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

clip-pathrotatetransition

モード1つが太陽・ダイヤル・温度を一緒に動かす

.th[data-mode="snow"] .th__sun { transform: translateY(16px); opacity: .45; }
.th[data-mode="sun"] .th__sun { transform: translateY(-8px); opacity: 1; }
.th[data-mode="cloud"] .th__sun { transform: translateY(4px); opacity: .7; }
.th[data-mode="flame"] .th__sun { transform: translateY(0); opacity: .85; }
.th[data-mode="snow"] .th__dial { transform: rotate(0deg); }
.th[data-mode="sun"] .th__dial { transform: rotate(90deg); }
.th__sun { transition: transform $duration $easing, opacity $duration $easing; }

アイコンボタンは data-mode 属性1つだけを差し替え、絵はすべて属性セレクタが受け持つので、スクリプトは属性と温度の数字しか書き換えません。晴れモードのときに雪モードを押すと太陽が 24px 下がって薄くなり、ダイヤルは90度から0度へ戻り、表示温度は27°から18°へ入れ替わります。山は三角形2つ、湖の反射は scaleX の往復です。

06レトロの太陽と遠近グリッド

ストライプの太陽とヤシ、足元へ流れる遠近グリッドで組んだ、ゲーム・音楽イベントのランディング向けシーンです。

レトロの太陽と遠近グリッド
新しいタブで開く

06 · レトロの太陽と遠近グリッド — 計測 累積面積 3.71% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

perspectiverotateXtext-shadow

グリッドは寝かせて、板ごと流す

.rt__floor {
  position: absolute; left: 0; right: 0; bottom: 0; height: 62px;
  perspective: 240px; overflow: hidden;
}
.rt__grid {
  position: absolute; left: -60%; top: -100%; width: 220%; height: 200%;
  transform: rotateX(58deg); transform-origin: top center;
  background:
    repeating-linear-gradient(90deg, rgba($grid-pink, .8) 0 2px, transparent 2px 44px),
    repeating-linear-gradient(0deg, rgba($grid-pink, .55) 0 2px, transparent 2px 36px);
  animation-name: rtGridFlow; animation-duration: $duration;
  animation-timing-function: linear; animation-iteration-count: infinite;
}
@keyframes rtGridFlow {
  from { transform: rotateX(58deg) translateY(0); }
  to { transform: rotateX(58deg) translateY(36px); }
}

床に perspective を置き、グリッド板を rotateX(58deg) で寝かせると横線が地平線に集まり、流れは background-position ではなく板そのものを1マス分(36px)ずらすので transform だけできれいにつながります。太陽の横の切れ目は下半分に舞台色の帯を重ねた膜で、タイトルは text-shadow 2枚のネオン、流星はループで短く走り、ボタンを押すと 96px を斜めに1回貫きます。

07水たまりグラデーション背景

絵の具がにじむように幾重にも広がる青緑・ピンク・紫の水たまりが暗い板の上でゆっくり揺れる、瞑想・旅行サービス向けの背景部品です。

水たまりグラデーション背景
新しいタブで開く

07 · 水たまりグラデーション背景 — 計測 累積面積 5.185% · 動いたフレーム 22/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

radialGradienttransform-originmix-blend-mode

水たまり1つは同じ色の楕円4枚

<g class="pl__blob pl__blob--teal">
  <ellipse cx="96" cy="84" rx="64" ry="44" fill="url(#plTeal)" opacity=".34"/>
  <ellipse cx="99" cy="81" rx="52" ry="35" fill="url(#plTeal)" opacity=".5" transform="rotate(-8 99 81)"/>
  <ellipse cx="93" cy="86" rx="40" ry="26" fill="url(#plTeal)" opacity=".7" transform="rotate(7 93 86)"/>
  <ellipse cx="98" cy="82" rx="29" ry="18" fill="url(#plTeal)" opacity=".9" transform="rotate(-4 98 82)"/>
  <ellipse cx="96" cy="84" rx="18" ry="11" fill="#29d8c0"/>
</g>

水たまり1つは中心を2〜3px ずつずらした楕円4枚と明るい芯1つで、縁が手描きのように波打つ理由は枚ごとに回転角と中心が違うからです。SVG の <g> も CSS トランスフォームを受け付けるので transform-box: fill-box を与えて1秒ごとに ±8度ずつ揺らし、重なる部分は mix-blend-mode: screen で明るく混ざります。クリックすると青緑が translate(-62px, -58px) へ、ピンクがその逆へ動いて色の位置が入れ替わります。

08ゲーム会社風ヒーロー背景

紫の光が揺らぎ、渦の帯がゆっくり回る暗いヒーロー背景で、ゲーム会社の紹介ページ向けの部品です。

ゲーム会社風ヒーロー背景
新しいタブで開く

08 · ゲーム会社風ヒーロー背景 — 計測 累積面積 13.677% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

repeating-conic-gradientanimation-directionfilter: blur

渦は放射状の縞をぼかして作る

.gh__swirl {
  position: absolute; right: -70px; top: -46px; width: 210px; height: 210px;
  border-radius: 50%;
  background: repeating-conic-gradient(rgba(138, 92, 214, .5) 0 14deg, rgba(138, 92, 214, 0) 14deg 42deg);
  -webkit-mask-image: radial-gradient(circle, rgba(0, 0, 0, 1) 0 52%, rgba(0, 0, 0, 0) 74%);
  mask-image: radial-gradient(circle, rgba(0, 0, 0, 1) 0 52%, rgba(0, 0, 0, 0) 74%);
  filter: blur(6px);
  animation-name: ghSwirl; animation-duration: $duration;
  animation-timing-function: ease-in-out; animation-iteration-count: infinite;
  animation-direction: alternate;
}
.gh.is-rev .gh__swirl { animation-direction: alternate-reverse; }

repeating-conic-gradient で扇形の縞を描き、blur(6px) で溶かし、放射状のマスクで縁を消すと、くるりと回る渦に見えます。向きの反転はクラス1つで animation-direction を alternate-reverse に変えるだけなので計算値もその場で変わり、紫の明滅は2秒周期、粒5つは時差で 96px ずつ浮かび上がります。

09トランク鞄の家

開いた古いトランク鞄の中に鏡・額・瞬く灯りの列・ソファ・ランプが入った、旅行・リビングブランドのストーリー画面向け部品です。

トランク鞄の家
新しいタブで開く

09 · トランク鞄の家 — 計測 累積面積 0.165% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · パスワードを見る

animation-delaybox-shadowtransition

6個の電球の時差と、温かさの重ね

.tk__bulb {
  position: absolute; width: 5px; height: 5px; border-radius: 50%;
  background: $stage-yellow;
  box-shadow: 0 0 6px rgba(255, 210, 63, .9);
  animation-name: tkTwinkle; animation-duration: $dur-loop;
  animation-timing-function: $ease-out; animation-iteration-count: infinite;
  animation-fill-mode: both;
}
@keyframes tkTwinkle {
  0%, 100% { opacity: .35; }
  18% { opacity: 1; }
  46% { opacity: .5; }
}
.tk__warm {
  position: absolute; inset: 0; opacity: 0; pointer-events: none;
  background: radial-gradient(circle at 72% 78%, rgba(255, 210, 63, .3) 0%, rgba(255, 210, 63, 0) 58%);
}

電球6個が 250ms 間隔で順に明るくなり、灯りの列が生きて息します。ランプを押すと傘の光と部屋全体を覆う温かさの重ねの opacity がそろって1まで上がりますが、重ねは HTML 上ランプより後ろにあって画面全体を覆うので、pointer-events: none を入れないとランプが押せません。この1行は、部品を作っている途中で実際にクリックが効かなくなり、その場で足したものです。

css アニメーション 例を図形だけで作るとき、まず何を決める?

図形だけで物を動かす css アニメーション 例を作るとき、最初に決めるのは何が動くかです。物の一部(ドラム・脚)だけが動くのか、物全体(近づく車)が動くのか、背景(路面・グリッド)が流れるのかを先に決めるとマークアップが自動的に決まります。9つのうち5つは物の一部の回転・拡大、4つは状態の切り替えなので、キーフレームアニメーションと transition を分けて使えました。2番目の決定は舞台の色で、インクの舞台に置いたクリームの洗濯機本体(01)は計測では強度が117.7まで出ましたが、同じ図形を明るい舞台に置くと下がるので、主役と舞台はセットで選びます。何から描けばいいか迷うときは、この記事のように一番大きな塊(本体・屋根・車体)を先に置いて穴(窓・ドア・ヘッドライト)を開ける順番がいちばん速いです。

どこで壊れるか — アニメーションは transition に勝つ

03 のハイビームは最初、動きませんでした。光には脈動するアニメーション(2秒で scale が .92↔1.08 を往復)をかけ、ボタンには scale(1.7) の transition をかけたのに、押しても計算値は脈動の途中値 matrix(0.96283) のままでした。CSS のカスケードではアニメーションの値が transition より常に優先されるなので、両者が同じプロパティを狙うと、transition がどれだけ速くても見えなくなるためです。直し方は、状態が点いている間だけアニメーションを切ることです。

.ca.is-beam .ca__glow {
  animation-name: none;
  transform: scale(1.7); opacity: 1;
}

animation-name: none の1行で脈動が退いて scale(1.7) の transition が現れ、もう一度消すと脈動が続きます。9つ分のファイルをまとめたアーカイブのパスワードは <span class="pw-inline" id="pw">5ak22r6m</span> で、展開すると素の版と React 版が並んで入っています。

3つのバリエーションとアクセシビリティ

名前 変える値 感じ
duration $dur-loop 2s → 4s ドラム・煙・グリッドの速度が半分になって、落ち着いた展示の場面になる
easing $ease-out → $ease-pop カラスの歩みと流星に1度の跳ねが付き、場面が跳ね上がる
color 舞台 ink → paper 同じ図形が夜のショールームから白いギャラリーへ移り、雰囲気が分かれる

どれも各 style.scss の先頭にある変数3行を書き換えるだけです。prefers-reduced-motion では9つすべてが回転・流れ・明滅を止めて、いちばん読みやすい静止ポーズを残します。ドラムは止まった水の上の靴下、家は昼の風景、カラスは文字の上に立った姿です。静止状態でも開始・停止・モード・ランプのボタンはそのまま押せます。

FAQ

html css アニメーション サンプルを物に使うとき、画像ファイルは必須ですか?

必須ではありません。この記事の9つはすべて角丸と clip-path・グラデーションの部品なので画像は0個で、ダウンロードする zip にも HTML と SCSS(または React 版2ファイル)しか入っていません。画像を使っていないので、色を変えるだけで別の物に生まれ変わります。

洗濯機のドラムのようにずっと回る物はバッテリーを食いませんか?

動かすのは transform と opacity に限っているので、レイアウトの再計算は起きず GPU が描きます。ただし1画面に複数を置くときは、animation-play-state で見えていない物を止めるのが安全で、このデモの開始・停止ボタンがまさにその役目です。

図形で描いた物が小さい画面でつぶれて見えるときは何を直せばいいですか?

ほとんどの場合、舞台の大きさと物の大きさのバランスです。デモは 480×300 を基準に、320px 幅でもはみ出さない狭い画面用の決まりを置いてあるので、物を大きくするときはまずこの決まりから見直してください。縦にはみ出すとグリッドのます目にスクロールバーが生えて、場面が切り取られます。

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

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