GODRICH

CSS 背景 アニメーション 9選 — 一行でコピペOK

css 背景 アニメーションは、CSSだけで背景を動かし続ける手法です。この記事では9種類を選び、background-positionとtransform、filter: blurという仕組みだけで実装しました。グリッドの9つはiframeの中で最初から動いていて、クリックでは止められません。

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

並び順は効果の派手さではなく、動きをどう組み立てるかという仕組みの難易度で決めました。まずbackground-positionだけを行き来させる基本形から始め(01)、それを複数のtransformレイヤーへ広げて奥行きを足し(02〜03)、繰り返しパターンを敷き詰めるgradientの重ね方に進み(04・06・07)、opacityとtransformだけでborder-radiusを毎フレーム再計算せずに形を変える手法を挟み(05)、回転させたレイヤーで見え方を変える書き方を経て(08)、最後にtransformの座標をpointermoveの値へ差し替えるだけで自動再生からカーソル追従へ切り替わる実装を並べました(09)。どの項目も動かしているのはbackground-positionかtransformのどちらかで、JavaScriptを使うのは09の座標の差し替えだけです。

01グラデーションの流れ

背景を実際の画面より二倍大きく敷き、background-positionだけを行き来させることで、グラデーションが波のように流れて見えます。ヒーローセクションの背景や、プレミアムなCTAボタンの背景に向いています。

background-position200% 200%ease-in-out
.stage::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: linear-gradient(120deg, $stage-ink, $color, $subject-cream, $stage-ink);
  background-size: 220% 220%;
  animation: flow $duration $easing infinite;
}

@keyframes flow {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

02メッシュグラデーションの漂い

色の異なるradial-gradientのにじみを3枚重ね、それぞれ違う周期でtransform: translateさせることで、にじみが有機的に混ざり合うメッシュグラデーションになります。SaaSのランディングヒーロー背景や、アプリのオンボーディング画面の背景に向いています。

radial-gradient 레이어transform: translate비동기 주기
.blob {
  position: absolute;
  width: 42%;
  aspect-ratio: 1;
  border-radius: 50%;
  filter: blur(12px);
}

.b1 { animation: drift1 $duration $easing infinite; }
.b2 { animation: drift2 $duration $easing infinite; animation-delay: -.6s; }
.b3 { animation: drift3 $duration $easing infinite; animation-delay: -1.2s; }

@keyframes drift1 {
  0%, 100% { transform: translate(0, 0); }
  50%      { transform: translate(48px, 32px); }
}

03オーロラブラー

filter: blurでぼかした小さな色の塊を3枚、半透明のまま重ね、transformの移動と回転だけで動かすことで、オーロラが重なり流れるような背景になります。ダークモードのヒーロー背景や、プレミアムなランディングの環境光演出に向いています。

filter: blur반투명 레이어transform 회전
.aurora {
  position: absolute;
  width: 38%;
  aspect-ratio: 1;
  border-radius: 50%;
  filter: blur(3px);
}

.a1 { animation: spin1 $duration linear infinite; }
.a2 { animation: spin2 $duration linear infinite; animation-delay: -1s; }

@keyframes spin1 {
  0%   { transform: translate(0, 0) rotate(0deg); }
  50%  { transform: translate(56px, 38px) rotate(180deg); }
  100% { transform: translate(0, 0) rotate(360deg); }
}

04動くグリッド線

repeating-linear-gradientを縦横二重に重ねてグリッド線を描き、background-positionを対角線方向へ動かすことで、グリッドが途切れず移動し続けているように見えます。開発者向けツールや技術ドキュメントのヒーロー、ダッシュボードの空状態背景に向いています。

repeating-linear-gradientbackground-position대각선 이동
.stage::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, rgba($color, .35) 1px, transparent 1px),
    linear-gradient(to bottom, rgba($color, .35) 1px, transparent 1px);
  background-size: 32px 32px, 32px 32px;
  animation: gridmove $duration linear infinite;
}

@keyframes gridmove {
  from { background-position: 0 0, 0 0; }
  to   { background-position: 32px 32px, 32px 32px; }
}

05ブロブモーフィング

形の違うブロブを3枚重ね、opacityとtransform(scale・rotate)だけを交互に動かすことで、border-radiusを毎フレーム再計算せずに一つの塊が形を変え続けるように見えます。アバウトページの装飾背景や、空状態(empty state)イラストの背景に向いています。

레이어 크로스페이드transform: scale·rotateopacity
.blob {
  position: absolute;
  width: 52%;
  aspect-ratio: 1;
}

.m1 { border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%; animation: morph1 $duration $easing infinite; }
.m2 { border-radius: 63% 37% 41% 59% / 55% 48% 52% 45%; opacity: 0; animation: morph2 $duration $easing infinite; }

@keyframes morph1 {
  0%   { opacity: 1; transform: scale(1) rotate(0deg); }
  38%  { opacity: 0; transform: scale(.94) rotate(8deg); }
  100% { opacity: 1; transform: scale(1) rotate(0deg); }
}

06ノイズグレイン

極小のrepeating-conic-gradientタイルを敷き詰め、background-positionをsteps()で毎フレーム飛ばすことで、フィルムグレインのようにチラつく質感になります。ダークヒーローのテクスチャオーバーレイや、プレミアムカード背景の淡いノイズに向いています。

repeating-conic-gradientsteps()background-position
.stage::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-conic-gradient(from 0deg, rgba($color, .55) 0deg 90deg, transparent 90deg 180deg);
  background-size: 3px 3px;
  opacity: .35;
  animation: grain $duration steps(40) infinite;
}

@keyframes grain {
  from { background-position: 0 0; }
  to   { background-position: 117px 69px; }
}

07動くドットパターン

radial-gradientで描いた小さなドットパターンをタイル状に並べ、background-positionを斜め方向へゆっくり流すことで、ドットが途切れなく流れて見えます。プレゼンやスライドの背景、カードグリッドの背後の背景に向いています。

radial-gradient 도트background-size 타일대각선 흐름
.stage::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle, rgba($color, .6) 1.5px, transparent 1.5px);
  background-size: 20px 20px;
  animation: dotdrift $duration linear infinite;
}

@keyframes dotdrift {
  from { background-position: 0 0; }
  to   { background-position: 20px 20px; }
}

08斜めストライプ移動

縦向きの縞模様を描いたレイヤーをまるごと45度回転させ、回転前の座標のまま横方向へbackground-positionを動かすことで、縞模様が斜めに行進しているように見えます。セールやプロモーションバナーの背景、処理中(processing)状態の背景に向いています。

repeating-linear-gradient45degbackground-position
.stage::before {
  content: "";
  position: absolute;
  inset: -150% -150%;
  transform: rotate(45deg);
  background-image: repeating-linear-gradient(90deg, rgba($color, .18) 0 18px, transparent 18px 36px);
  animation: stripemove $duration linear infinite;
}

@keyframes stripemove {
  from { background-position: 0 0; }
  to   { background-position: 36px 0; }
}

09カーソルスポットライト背景

ぼかした小さなradial-gradientの円をスポットライトとして、transform: translateで楕円軌道上に動かします。実際のページではこの座標をpointermoveの値に差し替え、カーソルに追従させます。インタラクティブなランディング背景や、ダークヒーローのポイント照明に向いています。

radial-gradient 스포트라이트transform: translatepointermove 대응
.spot {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 120px;
  height: 120px;
  margin: -60px 0 0 -60px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba($color, .55), transparent 70%);
  filter: blur(6px);
}

.spot.is-demo { animation: orbit $duration $easing infinite; }

@keyframes orbit {
  0%   { transform: translate(-90px, -40px); }
  50%  { transform: translate(70px, 60px); }
  100% { transform: translate(-90px, -40px); }
}

どこで崩れるか — 落とし穴

9つとも背景と要素の位置をbackground-positionかtransformのどちらかだけで動かしていて、幅や高さといった寸法の数値を書き換えるコードは一切ありません。ひとつ目に踏んだ壁は08の斜めストライプを組み立てているときのもので、45度に傾けたgradientそのものをその斜め方向へbackground-positionで動かしたところ、縞模様の向きと移動方向がぴったり重なり、画面はほとんど変化しませんでした。縦向きの縞を描いたレイヤーを別に用意し、それを丸ごとtransform: rotate(45deg)で回してから、回す前の横方向にbackground-positionを動かすことで、ようやく斜めに行進する見え方になりました。

ふたつ目は06のノイズグレインを組み立てていたときの話です。background-positionの動きにease-outのような滑らかな曲線を当てると、粒がひとかたまりのようになだらかに移動してしまい、フィルムのグレインらしいチラつきにはまったく見えませんでした。steps(40)へ差し替えて位置を毎フレーム飛び飛びに動かすと、粒がランダムに点滅するようなざらついた質感に変わりました。この差し替え済みの9ファイル一式を開く鍵は bc82wnvk という文字の並びで、下に置いたカードから取り出せます。

みっつ目は09のスポットライトを実ページへ組み込んだときのことです。デモの.is-demoはtransformで楕円軌道を勝手に描き続けますが、pointer: fineの判定を外してpointermoveのリスナーだけ付けたところ、タッチ操作しかできない端末で円が画面の隅に貼り付いたまま動かなくなりました。matchMedia('(pointer: fine)')で分岐を挟んだことで、マウスのある環境だけがカーソル追従へ切り替わるようになりました。

アクセシビリティ

9つとも prefers-reduced-motion: reduce では動きが止まりますが、要素そのものが消えるわけではありません。グラデーションの流れ(01)とグリッド線(04)、ノイズグレイン(06)、ドットパターン(07)、斜めストライプ(08)は最初のフレームの背景位置のまま静止し、メッシュグラデーション(02)とオーロラ(03)は各レイヤーが重なった位置で止まります。ブロブモーフィング(05)はopacity: 1の一枚だけが残り、スポットライト(09)は軌道の出発点で固定されます。この設定の詳しい挙動はMDNのprefers-reduced-motionの解説に載っています。

@media (prefers-reduced-motion: reduce) {
  .stage::before { animation: none; }
  .blob, .aurora { animation: none; }
  .m1 { opacity: 1; }
  .m2, .m3 { opacity: 0; }
  .spot.is-demo { animation: none; transform: translate(-90px, -40px); }
}

背景アニメーション以外のCSS作例はCSSカテゴリーの一覧ページにまとめてあり、この配布物を作っている運営については紹介ページで説明しています。

FAQ

すべて同じページに並べても動きは重なりませんか?

重なりません。それぞれのアニメーションは自分自身のクラス名にしか結び付いていないため、01のグラデーションと09のスポットライトを隣に並べても、片方のanimationがもう片方の要素へ影響することはありません。radial-gradientやfilter: blurを使う02・03・09も、レイヤーと座標がそれぞれの要素にスコープされているため同時に置いても問題は起きません。

背景を画面いっぱいに敷いても動作が重くなりませんか?

9つとも動かしているのはbackground-positionかtransformのどちらかで、レイアウトの再計算(リフロー)を引き起こすプロパティは使っていません。画面いっぱいに敷いても、ブラウザは背景レイヤーの合成だけで済ませるため、スクロールや文字の描画が目に見えて重くなることは基本的にありません。ただし06のような細かいタイルを敷き詰めるパターンは面積が広がるほど描くタイルの数も増えるので、極端に大きな画面では一度確認しておくと安心です。

Reactではこの動きをどう表示しますか?

zipのreact/フォルダにある各コンポーネントは、div要素にこれまでと同じクラス名を付けているだけで、動きの速さと軌道はCSSのanimation@keyframesが担います。09だけはpointer: fineの判定をuseEffectの中で行い、マウス環境のときだけpointermoveのイベントリスナーを登録してtransformの値を書き換えます。

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

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