- 技術 💻
Lottieとは?使い方とJSONの読み方、GIF・動画との容量比較
結論
Lottie(ロッティー)とは、図形の動きを JSON で書き表したベクターアニメーションの形式です。Web では lottie-web を読み込み、lottie.loadAnimation() に表示する要素と JSON の場所を渡すだけで再生でき、再生・停止・速度・区間をプログラムから操作できます。
この記事でわかること
- 手で書いた 1,429 バイトの Lottie JSON を Chromium で動かした結果と、JSON の読み方
- 同じ動きの GIF・MP4・WebM・CSS・SVG との容量と CPU の実測値
- dotLottie・React・Vue での使い方と、表示されない・重い・文字が崩れる原因
Lottie は「デザイナーが作った動きを、動画ではなくデータとして渡し、ブラウザやアプリがその場で描く」仕組みです。流れを図にすると次のとおりです。
flowchart TD
A[After Effects などで動きを作る] --> B[Bodymovin などで書き出す]
B --> C[Lottie JSON<br>図形・キーフレーム]
C --> D[ZIP にまとめると<br>dotLottie .lottie]
C --> E[lottie-web などのプレイヤー]
D --> F[dotlottie-web など]
E --> G[SVG・Canvas で描画]
F --> G
よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| Lottieとは | 図形の動きを JSON で表したベクターアニメーションの形式 | Lottieとは |
| Lottie の使い方(Web) | lottie-web を読み込み、loadAnimation に container と path を渡す | lottie-webの使い方 |
| JSON の中身の読み方 | 上から fr・op・w・h、layers の中の ks(動き)と shapes(形) | Lottie JSONの構造 |
| 再生・停止・ループ・速度 | play・pause・stop・setSpeed・loop・playSegments | 再生の操作 |
| GIF・動画より軽いか | データは軽いが、再生には 46〜76KB(gzip)のライブラリが要る | 容量とCPUの比較 |
| dotLottie(.lottie)との違い | JSON と画像などを ZIP にまとめた形式。専用プレイヤーで再生 | dotLottieとは |
| React・Vue で使う | React は lottie-react、Vue は lottie-web を onMounted で読み込む | React・Vueでの使い方 |
| 表示されない・重い | JSON の 404・file:// で開いた・同時再生が多い・フォントが無い | よくある不具合 |
確認環境:Ubuntu 24.04.5 LTS の上で、Node.js 22.23.4・npm 10.9.9 を使い、作業用のフォルダーに lottie-web 5.13.0・@lottiefiles/dotlottie-web 0.82.0・lottie-react 3.1.2・React 19.3.1・Vue 3.5.44・esbuild を入れました。Lottie JSON は素材サイトのものを使わず手で書き(400×200・30fps・60フレーム)、Python 3.13 の http.server で 127.0.0.1 に置いて、Chromium 153.0.8010.12(Playwright 1.63.0 から操作、ヘッドレス)で再生・操作・エラーの再現・CPU の測定を行いました。外部への通信は遮断し、0件であることを確かめています。GIF・MP4・WebM・WebP は ffmpeg 6.1.1 で作りました。After Effects と Bodymovin の操作、LottieFiles の各ツールは手元で動かしておらず、lottie-web の README と LottieFiles の公式ページで確かめた範囲で書いています。JSON の各項目の意味は Lottie Specification 1.0.1、dotLottie は dotLottie 2.0 Specification、ライセンスは Lottie Simple License の公式ページで確かめました。図は mermaid 11.16.0 で描画を確かめています(確認日 2026年10月29日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Lottieとは?使い方とJSONの読み方、GIF・動画との容量比較」
Lottieとは(JSONで書かれたベクターアニメーション)
この節では、Lottie が何で、誰が作り、どんな場面で使われているかが分かります。
Lottie は、ベクター(点と線の座標で表す図形)のアニメーションを JSON で記述するファイル形式と、それを再生するライブラリ群の呼び名です。 仕様を管理する Lottie Animation Community(LAC)は、Lottie を「オープンソースのベクターグラフィックス・アニメーションのファイル形式」と説明しています。
始まりは 2015 年に Hernan Torrisi さんが作った After Effects の書き出しプラグイン Bodymovin で、のちに Airbnb が iOS・Android・Web 向けの再生ライブラリを公開して「Lottie」の名前で広まりました。現在、形式の仕様は Linux Foundation がホストする LAC が策定しており、2026年10月29日時点の公開版は Lottie Specification 1.0.1 です。LAC のサイトは、拡張子として .lot、MIME タイプとして video/lottie+json を挙げつつ、従来どおり .json が広く使われているとも書いています。
1拡大してもぼやけない
中身は座標と色の数値なので、400×200 で作った動きを 800×400 で表示しても輪郭がにじまない。GIF や動画は大きく表示するほど粗くなる。
2データが小さい
この記事で手書きした円と四角の2秒の動きは 1,429 バイト(gzip で 411 バイト)。同じ動きの GIF は 69,873 バイトだった。
3プログラムで操作できる
再生・停止・速度・逆再生・指定区間だけの再生を JavaScript から行える。ボタンの状態に合わせて動きを切り替える用途に向く。
使われる場面は、読み込み中の表示、ボタンを押したときの反応、空の状態・完了画面のイラスト、アプリのオンボーディング(初回の説明画面)などです。LottieFiles は、メッセージアプリのステッカーや家電・テレビのシステムアニメーションでも使われていると紹介しています。
Lottie にまつわる名前の整理
| 名前 | 何か | この記事での扱い |
|---|---|---|
| Lottie | 形式(JSON)と、再生ライブラリ群の総称 | 形式として説明 |
| lottie-web | Airbnb が公開する Web 用の再生ライブラリ(npm の lottie-web) | 5.13.0 を Chromium で実行 |
| Bodymovin | After Effects から Lottie JSON を書き出すプラグイン | 手順は公式 README の範囲 |
| LottieFiles | Lottie の素材共有・編集サービスを運営する会社とサイト | ライセンスを公式で確認 |
| dotLottie(.lottie) | Lottie JSON と画像などを ZIP にまとめた形式 | 自作して dotlottie-web で再生 |
| LAC | Lottie の仕様を策定する団体(Linux Foundation がホスト) | 仕様 1.0.1 で JSON の意味を確認 |
Lottie JSONの構造の読み方(layers・shapes・keyframes)
この節では、Lottie の JSON を開いたときに、どこに何が書かれているかを読めるようになります。
Lottie JSON は「画面の大きさと時間」→「レイヤー(層)」→「形と動き」の3段で読みます。 この記事では素材サイトのファイルを使わず、青い円が左右に往復し、橙の角丸四角が1回転する2秒の動きを手で書きました。円のレイヤーだけを抜き出すと次のとおりです。
{
"v": "5.7.4", "fr": 30, "ip": 0, "op": 60, "w": 400, "h": 200,
"nm": "rjc-demo", "ddd": 0, "assets": [],
"layers": [
{
"ty": 4, "nm": "ball", "ind": 1, "ip": 0, "op": 60, "st": 0,
"ks": {
"o": { "a": 0, "k": 100 },
"r": { "a": 0, "k": 0 },
"p": { "a": 1, "k": [
{ "t": 0, "s": [60, 140, 0], "o": {"x":[0.42],"y":[0]}, "i": {"x":[0.58],"y":[1]} },
{ "t": 30, "s": [340, 140, 0], "o": {"x":[0.42],"y":[0]}, "i": {"x":[0.58],"y":[1]} },
{ "t": 60, "s": [60, 140, 0] }
]},
"a": { "a": 0, "k": [0, 0, 0] },
"s": { "a": 0, "k": [100, 100, 100] }
},
"shapes": [
{ "ty": "gr", "nm": "circle", "it": [
{ "ty": "el", "p": { "a": 0, "k": [0, 0] }, "s": { "a": 0, "k": [60, 60] } },
{ "ty": "fl", "c": { "a": 0, "k": [0.12, 0.44, 0.85, 1] }, "o": { "a": 0, "k": 100 }, "r": 1 },
{ "ty": "tr", "p": { "a": 0, "k": [0, 0] }, "a": { "a": 0, "k": [0, 0] },
"s": { "a": 0, "k": [100, 100] }, "r": { "a": 0, "k": 0 }, "o": { "a": 0, "k": 100 } }
]}
]
}
]
}
1段目:画面の大きさと時間
| キー | 意味 | この例の値 |
|---|---|---|
| fr | 1秒あたりのフレーム数 | 30 |
| ip・op | 開始と終了のフレーム。ip が 0 なら op が長さ(フレーム数) | 0・60(=2秒) |
| w・h | 描画の幅と高さ | 400・200 |
| layers | レイヤーの配列。先頭ほど手前に描かれる | ball・square の2枚 |
| assets | 画像やプリコンポジション(入れ子の動き)の置き場 | 空 |
| v・nm | v は書き出したツールの版、nm は名前 | 5.7.4・rjc-demo |
仕様 1.0.1 では、対象とする仕様の版を ver(6桁の数字)で書く項目も定義されています。Bodymovin が書き出すファイルでよく見る v は書き出し側の版で、別のものです。
2段目:レイヤーの種類(ty)
| ty | レイヤー | 中身 |
|---|---|---|
| 0 | プリコンポジション | assets にある別の動きを入れ子で使う |
| 1 | 平面(Solid) | 単色の四角 |
| 2 | 画像 | assets の画像を表示 |
| 3 | ヌル | 何も描かず、親として他のレイヤーを動かす |
| 4 | シェイプ | shapes に図形を持つ。手書きの例はすべてこれ |
| 5 | テキスト | 文字。lottie-web は再生できるが、仕様 1.0.1 のレイヤー一覧には無い |
レイヤーの ks は変形(transform)で、a(アンカーポイント)・p(位置)・s(拡大率、100 が等倍)・r(回転、度)・o(不透明度、100 が不透明)が入ります。
3段目:形(shapes)と動き(keyframes)
shapes の中は ty の2文字で種類が決まります。gr(グループ)の it に、形→塗り→変形の順に並べるのが基本です。
形
el 楕円、rc 長方形、sr 星・多角形、sh 自由な線(パス)。
s が大きさ、p が中心
塗りと線
fl 塗り、st 線、gf・gs グラデーション。
色は 0〜1 の RGBA
変形と加工
tr グループ内の変形、tm パスのトリミング(線が伸びる表現)。
tr はグループの最後
動き
"a": 1 のとき k がキーフレームの配列になる。"a": 0 なら k は値そのもの。
a は animated の a
キーフレームは t(フレーム番号)と s(その時点の値)の組です。o と i はイージング(速さの変化)の曲線で、CSS の cubic-bezier(0.42, 0, 0.58, 1)(ease-in-out)と同じ形を o に (0.42, 0)、i に (0.58, 1) として書いています。"h": 1 を付けると、次のキーフレームまで値を変えずに保ちます。色は 0〜255 ではなく 0〜1 で、[0.12, 0.44, 0.85, 1] は CSS の #1f70d9 にあたります。
lottie-web が JSON から作った SVG
この JSON を lottie-web の SVG レンダラーで読み込み、15 フレーム目(0.5秒)で止めて DOM を読み出すと、次の値でした。
svg の属性: viewBox="0 0 400 200" width="400" height="200" preserveAspectRatio="xMidYMid meet"
svg の中の要素数: 10
四角のグループ: transform="matrix(0,1,-1,0,200,55)" ← 90度回転(60フレームで360度の4分の1)
円のグループ: transform="matrix(1,0,0,1,200,140)" ← x=200(60と340の中間)
円の path: d=" M0,-30 C16.55699920654297,-30 30,-16.55699920654297 30,0 C3..."
楕円(el)はベジェ曲線の path に変換され、位置と回転は毎フレーム transform の行列として書き換えられます。JSON を読むときは「ks が動き、shapes が形」と覚えておくと、どの数字を変えれば何が変わるかを追えます。
fr と op で長さを知る
op ÷ fr が秒数。この例は 60 ÷ 30 で2秒。
layers の nm と ty を一覧にする
名前と種類で、どのレイヤーが何を描いているかの見当を付ける。
ks で "a": 1 の項目を探す
動いているのは a が 1 の項目だけ。t と s を並べると、いつ何がどう変わるかが読める。
shapes で形と色を確かめる
el・rc・sh で形、fl・st で色。色を変えたいときは c の数値を書き換える。
JSON そのものの書き方や、構文エラーの読み方は、関連記事「JSONとは|JSONファイルの書き方・開き方とエラー例を実物で解説」で扱っています。
Lottieの使い方:lottie-webでWebページに表示する
この節では、Lottie を HTML に表示する最小の手順と、loadAnimation の設定項目が分かります。
必要なのは、lottie-web の JavaScript、Lottie JSON、表示する要素の3つです。 npm で入れた場合、ブラウザでそのまま読めるファイルは node_modules/lottie-web/build/player/ にあります。
npm install lottie-web
ls node_modules/lottie-web/build/player/
# lottie.min.js lottie_light.min.js lottie_svg.min.js lottie_canvas.min.js ほか
<!doctype html>
<html lang="ja">
<head><meta charset="utf-8"><title>Lottie</title></head>
<body>
<section id="lottie" style="width:400px;height:200px" role="img" aria-label="読み込み中"></section>
<script src="lottie.min.js"></script>
<script>
const anim = lottie.loadAnimation({
container: document.getElementById('lottie'), // 表示する要素
renderer: 'svg', // 'svg' / 'canvas' / 'html'
loop: true, // true / false / 回数
autoplay: true, // 読み込んだら自動で再生
path: 'demo.json' // JSON の場所(animationData とどちらか一方)
});
</script>
</body>
</html>
このページを 127.0.0.1 の HTTP サーバーから開くと、JSON の取得から描画までのイベントは次の順で起きました(DOMLoaded の時刻を 0 とした相対値)。
config_ready → data_ready → DOMLoaded → loopComplete@1988ms → loopComplete@4005ms → loopComplete@6005ms
loadAnimation の設定項目
| 項目 | 値 | 手元で確かめたこと |
|---|---|---|
| container | 表示する DOM 要素 | null を渡すとエラーも出ず、何も表示されない |
| renderer | 'svg'・'canvas'・'html' | svg は要素10個の SVG、canvas は canvas 1枚 |
| loop | true・false・数値 | 2 にすると3回再生して止まった(最初の1回+2回) |
| autoplay | true・false | false なら play() まで1フレーム目で止まる |
| path | JSON の URL | 404 なら data_failed イベントが起きる |
| animationData | 読み込み済みの JSON オブジェクト | path と同時には使わない |
| name | 名前 | lottie.play('名前') のように全体の操作で指定できる |
| rendererSettings | preserveAspectRatio など | 既定は xMidYMid meet(縦横比を保って収める) |
README には、同じ animationData を何度も loadAnimation に渡す場合、リピーターを含む動きではオブジェクトを複製してから渡すよう注意書きがあります。
file:// で開くと表示されない
HTML ファイルをダブルクリックして file:// で開くと、path の JSON を取得できず、何も表示されません。Chromium のコンソールには次の原文が出ました。
Access to XMLHttpRequest at 'file:///dev/shm/t135/site/demo.json' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: chrome, chrome-extension, chrome-untrusted, data, http, https, isolated-app.
Failed to load resource: net::ERR_FAILED
lottie-web 側では data_failed イベントが起きています。手元で確かめるときは python3 -m http.server 8000 --bind 127.0.0.1 などで HTTP サーバーを立てて開くか、JSON を JavaScript に埋め込んで animationData で渡します。
どのビルドを読み込むか
build/player には描画方式ごとのファイルがあります。大きさは次のとおりでした(gzip は gzip -9 で圧縮した値)。
| ファイル | そのまま | gzip | 違い |
|---|---|---|---|
| lottie.min.js | 305,704 バイト | 76,054 バイト | 全部入り(svg・canvas・html と Expressions) |
| lottie_svg.min.js | 242,630 バイト | 62,320 バイト | SVG だけ |
| lottie_light.min.js | 168,394 バイト | 46,410 バイト | SVG だけで Expressions を含まない |
軽量版で困るのは Expressions(After Effects の式で動きを計算する機能)です。四角の回転を式 $bm_rt = time * 180; に置き換えた JSON を1秒の位置で止めると、全部入りでは matrix(-1,0,0,-1,200,55)(180度)でしたが、lottie_light では matrix(1,0,0,1,200,55) のまま回りませんでした。エラーは出ないため、軽量版に替えるときは書き出し側で式を使っていないかを先に確かめます。
Lottieの再生・停止・速度・ループ・区間を操作する
この節では、lottie-web のメソッドで再生を操作したときに、実際にどのフレームに進むかが分かります。
loadAnimation が返すオブジェクトに play・pause・stop・setSpeed・setDirection・goToAndStop・playSegments などがあります。 60フレーム(30fps・2秒)の JSON で、それぞれを実行した結果です。
| 操作 | 書き方 | 実行結果 |
|---|---|---|
| 長さを調べる | getDuration()・getDuration(true) | 2(秒)・60(フレーム) |
| 再生 | play() | 500ミリ秒後に 14.50 フレーム |
| 一時停止 | pause() | 300ミリ秒待っても同じフレームのまま |
| 停止 | stop() | 0 フレームに戻る |
| 2倍速 | setSpeed(2) | 500ミリ秒後に 29.99 フレーム |
| 逆再生 | setDirection(-1) | 50 から始めて500ミリ秒後に 35.00 |
| 区間だけ再生 | playSegments([0, 30], true) | 957ミリ秒で complete、29 で止まる |
| 指定位置で止める | goToAndStop(15, true) | 15 フレーム目を表示 |
| 片付け | destroy() | container の子要素が 0 になり destroy イベント |
つまずきやすい3つの動き
goToAndStop の単位
goToAndStop(1) で1秒の位置へ行く。実際は第2引数を省くとミリ秒扱いで、1ミリ秒(回転 0.18 度)の位置だったgoToAndStop(1000)、フレームなら goToAndStop(30, true)。どちらも 30 フレーム目になった第2引数 isFrame を毎回書くと読み違えない
playSegments のあとのループ
goToAndPlay(0, true) すれば全体に戻る。実際は totalFrames が 30 のままで、1秒ごとに loopComplete が起きたresetSegments(true) を呼ぶ。totalFrames が 60 に戻り、2秒ごとの loopComplete になった区間の指定は解除するまで残る
loop に数値を渡す
loop: 2 で2回再生する「繰り返す回数」と読む
なめらかさ(setSubframe)
lottie-web は既定でブラウザの描画のたびに中間の値を計算します。requestAnimationFrame ごとに currentFrame を読むと、既定(setSubframe(true))では 0.5, 1, 1.5, 2… と 0.5 刻み、setSubframe(false) では 0, 1, 2, 3… と JSON の fr どおりの整数でした。30fps で作った動きでも、60Hz の画面では 60 回描かれるということです。わざとカクカクさせたいとき以外は既定のままにします。
イベントで後続の処理をつなぐ
anim.addEventListener('DOMLoaded', () => console.log('描画の準備ができた'));
anim.addEventListener('complete', () => button.disabled = false); // loop: false の終わり
anim.addEventListener('loopComplete', () => count++); // 1周ごと
anim.addEventListener('data_failed', () => fallback.hidden = false); // JSON を取れなかった
README に載っているイベントは complete・loopComplete・enterFrame・segmentStart・config_ready・data_ready・data_failed・loaded_images・DOMLoaded・destroy です。enterFrame は毎フレーム起きるため、重い処理を書かないようにします。
LottieとGIF・MP4・CSS・SVGの容量とCPUを同じ動きで比較
この節では、同じ動きを各形式で作ったときに、ファイルの大きさとブラウザの負荷がどれだけ違うかが分かります。
データの大きさは Lottie JSON が GIF の約49分の1でしたが、再生ライブラリを含めると動画と同じくらいになり、CPU は CSS・GIF・動画より多く使いました。 「Lottie は軽い」は、データの話としては正しく、再生の負荷の話としては条件しだいです。
比べ方
- 動き:400×200 の白地で、青い円が ease-in-out で左右に往復し、橙の角丸四角が等速で1回転する2秒の繰り返し。
- Lottie:手書きの JSON を lottie-web 5.13.0(svg・canvas)と dotlottie-web 0.82.0 で再生。
- GIF・MP4・WebM・アニメーション WebP:lottie-web で 0〜59 フレームを1枚ずつ Chromium で撮影し、ffmpeg 6.1.1 で 30fps に変換(GIF は 64 色のパレット、MP4 は H.264 の CRF 23、WebM は VP9 の CRF 33)。
- CSS:
@keyframesとtransform、同じ cubic-bezier。SVG:SMIL のanimate・animateTransformを img で表示。 - CPU:ヘッドレスの Chromium 153 で表示し、2秒待ってから10秒間に Chromium の全プロセスが使った CPU 時間(/proc の値)と、Performance.getMetrics のメインスレッドの処理時間を測定。1個は3回の中央値、20個は2回の平均。GPU の無い環境のため描画はソフトウェア(SwiftShader)で、2 CPU の共有マシンでの値です。
ファイルの大きさ(同じ動き)
| 形式 | 400×200 | 800×400(高解像度向け) | 別に要るもの |
|---|---|---|---|
| Lottie JSON | 1,429 バイト(gzip 411) | 同じ(拡大は描画側) | lottie-web:gzip 46,410〜76,054 |
| dotLottie | 680 バイト | 同じ | JS gzip 30,739+wasm gzip 491,437 |
| GIF | 69,873 バイト | 147,289 バイト | なし |
| アニメーション WebP | 70,460 バイト | 137,060 バイト | なし |
| MP4(H.264) | 14,857 バイト | 24,910 バイト | なし |
| WebM(VP9) | 12,206 バイト | 20,903 バイト | なし |
| CSS | 584 バイト(gzip 314) | 同じ | HTML の要素2つ |
| SVG(SMIL) | 539 バイト(gzip 349) | 同じ | なし |
ライブラリはページに1回読み込めば、動きがいくつ増えても増えません。同じページに動きを3つ以上置く、高解像度の画面にくっきり出したい、という条件で Lottie の容量の利点が大きくなります。 逆に、ページに1つだけ置く単純な動きなら、CSS か SVG のほうが小さく済みます。
CPU(1個を表示)
| 形式 | Chromium 全体の CPU | メインスレッド | JS ヒープ |
|---|---|---|---|
| 何も置かない | 0.1% | 0.0% | 1.61MB |
| GIF | 4.3% | 0.1% | 1.71MB |
| CSS | 4.5% | 0.1% | 1.70MB |
| MP4(H.264) | 4.8% | 0.2% | 1.73MB |
| WebM(VP9) | 5.0% | 0.2% | 1.73MB |
| Lottie(canvas) | 7.8% | 2.9% | 3.29MB |
| dotLottie | 7.8% | 3.4% | 2.49MB |
| Lottie(svg) | 8.8% | 3.1% | 3.21MB |
| SVG(SMIL) | 10.7% | 2.6% | 1.71MB |
CPU(20個を同時に表示)
| 形式 | Chromium 全体の CPU | メインスレッド | JS ヒープ |
|---|---|---|---|
| GIF | 13.0% | 0.0% | 1.73MB |
| CSS | 19.7% | 0.1% | 1.72MB |
| MP4(H.264) | 24.1% | 0.9% | 1.23MB |
| Lottie(svg) | 28.5% | 8.3% | 7.0〜8.4MB |
| SVG(SMIL) | 32.1% | 3.5% | 1.73MB |
| Lottie(canvas) | 33.2% | 22.3% | 6.8〜7.0MB |
| dotLottie | 38.3% | 29.3% | 4.8〜4.9MB |
1Lottie はメインスレッドを使う
GIF・CSS・動画はメインスレッドをほぼ使わない(0.1〜0.9%)。Lottie は毎フレーム JavaScript で値を計算するため、20個で 8〜29% を使い、クリックなどへの反応と取り合う。
2この環境では canvas より svg が軽かった
GPU の無いソフトウェア描画では、canvas は描画もメインスレッドで行うため、20個で svg の約2.7倍のメインスレッド時間になった。GPU のある端末では結果が変わりうるので、対象の端末で測る。
3SVG の SMIL も軽くはない
容量は最小級だが、1個で 10.7% と今回いちばん CPU を使った。単純な動きを軽く出すなら CSS の transform が最も安定していた。
メインスレッドが忙しいと、ボタンを押してから画面が変わるまでの時間(INP)が延びます。測り方と直し方は関連記事「INP改善の方法|Core Web Vitalsの原因別コードと改善前後の実測値」で扱っています。
dotLottie(.lottie)とは:Lottie JSONとの違い
この節では、dotLottie が JSON とどう違い、どんなときに選ぶかが分かります。
dotLottie は、Lottie JSON と画像・テーマ・状態遷移(ステートマシン)などを1つの ZIP にまとめた形式で、拡張子は .lottie です。 LottieFiles が開発しており、仕様は dotlottie.io で公開されています(2026年10月29日時点の最新は 2.0)。LAC のサイトも、dotLottie は Lottie を土台にした別の形式だと説明しています。
仕様 2.0 の構成は、ZIP の直下に manifest.json(必須)と a/(アニメーション、必須)、必要に応じて i/(画像)・s/(ステートマシン)・t/(テーマ)・f/(フォント)を置く形です。圧縮方式は Deflate、MIME タイプは application/zip+dotlottie です。手で作ると次のようになります。
import zipfile, json
with zipfile.ZipFile("demo.lottie", "w", zipfile.ZIP_DEFLATED) as z:
z.writestr("manifest.json", json.dumps({"version": "2", "animations": [{"id": "demo"}]}))
z.write("demo.json", "a/demo.json") # id と同じ名前で a/ に置く
$ unzip -l demo.lottie
Length Date Time Name
--------- ---------- ----- ----
77 2026-10-30 21:19 manifest.json
1429 2026-10-30 21:13 a/demo.json
--------- -------
1506 2 files
$ wc -c demo.lottie
680 demo.lottie
再生には LottieFiles の dotlottie-web(0.82.0)を使いました。描画は Rust 製のエンジンを WebAssembly にしたもので、canvas に描きます。
import { DotLottie } from '@lottiefiles/dotlottie-web';
DotLottie.setWasmUrl('/dl/dotlottie-player.wasm'); // 自分のサーバーの wasm を使う
const player = new DotLottie({
canvas: document.getElementById('c'),
src: '/demo.lottie',
loop: true,
autoplay: true
});
player.addEventListener('load', () => console.log(player.totalFrames, player.duration)); // 60 2
Chromium で実行すると load・play・frame・loop の順にイベントが起き、totalFrames は 60、duration は 2、manifest は {"version":"2","generator":"hand-written",...} と読めました。
| 比べる点 | Lottie JSON(lottie-web) | dotLottie(dotlottie-web) |
|---|---|---|
| この例のファイル | 1,429 バイト(gzip 配信で 411 バイト) | 680 バイト(ZIP 済み) |
| プレイヤーの大きさ | JS 305,704 バイト(gzip 76,054) | JS 158,745(gzip 30,739)+ wasm 1,226,030(gzip 491,437) |
| 描画先 | SVG・Canvas・HTML | Canvas(WebGL・WebGPU 版もある) |
| 画像・複数の動き | 画像は別ファイルか Base64 で JSON に埋め込む | 1ファイルにまとめられる |
| テーマ・状態遷移 | 自分で JavaScript を書く | 形式として持てる |
| 中身を読む | テキストエディタでそのまま | unzip してから |
サーバーが JSON を gzip で配信するなら、小さな動き1つでは JSON のほうが転送量は小さくなりました。dotLottie が効くのは、画像を含む動きや、複数の動き・テーマを1ファイルで配りたいときです。
dotlottie-web で注意したこと
wasm の取得先
既定では cdn.jsdelivr.net(失敗時は unpkg.com)から wasm を取得する作りになっている
外部へ出られない環境や、配信元を自社に限りたいときは setWasmUrl() で自分のサーバーを指す
この記事の実行では外部への要求を遮断し、0件だったことを確かめた
ZIP の中の置き場所
version "2" の manifest で animations/demo.json に置いた .lottie は、load も loadError も起きず何も表示されなかった
a/demo.json に直すと再生できた
version "1" の manifest と animations/ の組み合わせ(1.0 の形)は再生できた
React・VueでLottieを使う方法
この節では、React と Vue で Lottie を表示する最小のコードと、版の違いでつまずく点が分かります。
React は lottie-react、Vue は lottie-web を onMounted で読み込む形が最小です。 どちらも esbuild でまとめて Chromium で表示し、SVG が描かれることを確かめました。
React(lottie-react 3)
npm install lottie-react react react-dom
import { createRoot } from 'react-dom/client';
import { Lottie } from 'lottie-react';
import demo from './demo.json';
function App() {
return (
<section style={{ width: 400, height: 200 }}>
<Lottie src={demo} autoplay loop />
</section>
);
}
createRoot(document.getElementById('root')).render(<App />);
esbuild でまとめて Chromium で開くと、viewBox="0 0 400 200" の SVG が描かれ、300ミリ秒後に変形の値が変わる(再生している)ことを確かめました。lottie-react は SVG を自前の div で包んで描きます。注意したいのは版の違いです。3.x には default の書き出しが無く、2.x の書き方 import Lottie from 'lottie-react'(animationData を渡す形)のままだと、esbuild は No matching export in "../node_modules/lottie-react/build/index.js" for import "default" で止まりました。3.x は名前付きの { Lottie } と src を使います。検索で見つかる記事の多くは 2.x の書き方なので、package.json の版を先に確かめます。
Vue 3(lottie-web を直接使う)
import { createApp, h, ref, onMounted, onBeforeUnmount } from 'vue';
import lottie from 'lottie-web';
import demo from './demo.json';
const LottieView = {
setup() {
const el = ref(null);
let anim;
onMounted(() => {
anim = lottie.loadAnimation({ container: el.value, renderer: 'svg', loop: true, autoplay: true, animationData: demo });
});
onBeforeUnmount(() => anim?.destroy()); // 外すときに必ず破棄する
return () => h('section', { ref: el, style: 'width:400px;height:200px' });
}
};
createApp(LottieView).mount('#app');
同じく Chromium で開くと SVG が描かれ、currentFrame が進みました。app.unmount() を呼ぶと onBeforeUnmount の destroy() が動き、destroy イベントが起きています。破棄を書き忘れると、画面を切り替えるたびに再生中のアニメーションが残り、メモリと CPU を使い続けます。Vue 用のラッパーのパッケージもありますが、lottie-web を直接使う形なら版の違いに左右されにくくなります。
Vue の Transition で要素の出入りに動きを付ける方法は、関連記事「Vue Transitionの使い方|フェード・スライドのコード集」で扱っています。Lottie はイラストのような複雑な動きを、Transition は表示・非表示の切り替えを受け持つと考えると分けやすくなります。
Lottieの作り方:After Effects+Bodymovinと他の方法
この節では、Lottie のファイルを作る方法と、書き出せない表現が分かります。
代表的なのは、Adobe After Effects で動きを作り、Bodymovin で JSON に書き出す方法です。 lottie-web の README に書かれている手順は次のとおりです(After Effects は手元で動かしていないため、公式 README の範囲で書いています)。
Bodymovin のパネルを開く
After Effects のプロジェクトを開き、ウィンドウ → エクステンション → bodymovin を選ぶ。
コンポジションを選ぶ
Compositions タブに一覧が出るので、書き出すものを選ぶ。
保存先を決めて Render
書き出し先のフォルダーを選んで Render を押す。
JSON と images を確かめる
画像や Illustrator のレイヤーを含むと、JSON と別に images フォルダーができる。
README が挙げる対応範囲は、プリコンポジション・シェイプ・平面・画像・ヌル・テキスト・マスク・タイムリマップ・Expressions です。画像の連番・動画・音声は書き出せず、レイヤーの時間を負の値で伸縮すると崩れるとも書かれています。エフェクト(ぼかし・グローなど)は再生ライブラリごとに対応が違うため、使う前に対象のプレイヤーで再生して確かめます。
After Effects 以外の作り方
- LottieFiles のツール:LottieFiles は、After Effects 用の自社プラグイン、Figma からの書き出し、SVG を Lottie に変換するツール、ブラウザ上の Lottie エディターを案内しています(各ツールは LottieFiles のアカウントが要るものがあり、この記事では使っていません)。
- 手で書く・プログラムで作る:この記事のように、単純な図形の移動・回転なら JSON を直接書けます。数値を変えるだけで色や速さを変えられるので、生成スクリプトとの相性もよい形式です。
- 既存の JSON を直す:色の
c、長さのop、位置のpなどをテキストで書き換えられます。書き換えたら JSON の構文が壊れていないかを必ず確かめます(壊れたときの症状は後の節)。
LottieFilesの素材とライセンス
この節では、LottieFiles の無料素材を使うときに確かめる条件が分かります。
LottieFiles の無料の公開素材は「Lottie Simple License」で配布されており、商用を含めて利用・改変・配布ができ、作者の表記は必須ではありません。 2026年10月29日時点の公式のライセンスページ(FL 9.13.21)で確かめた主な条件は次のとおりです。
| 項目 | Lottie Simple License の記載 |
|---|---|
| できること | ダウンロード・複製・改変・公開・配布・表示。商用目的も含む |
| 作者の表記 | 表記なしで使ってよい。ただし表記は強く推奨され、表記するなら利用者に見える形で |
| 改変したもの | 派生物として扱われる |
| 再配布 | 同じライセンスの条件を付けて配る。別の条件や技術的な制限を足してはいけない |
| できないこと | LottieFiles から素材を集めて、似たサービスを作るための収集 |
| 保証 | 現状のまま(AS IS)で、保証はない |
注意したいのは、このライセンスが適用されるのは「LottieFiles 上で公開されている無料の素材」だという点です。有料のマーケットプレイスの素材や、他のサイトで配られている素材は、それぞれの条件を個別に読みます。また、ライセンスのページは商標やロゴに触れていません。企業のロゴや他社のキャラクターを含む素材は、Lottie のライセンスとは別に権利者の許可が要る可能性があるため、業務では使わないか、法務に確かめてから使います。
この記事では、素材サイトの取得による権利の混同を避けるため、使った Lottie JSON はすべて手で書いています。
Lottieのアクセシビリティ:prefers-reduced-motionと一時停止
この節では、動きが苦手な人に配慮した Lottie の組み込み方が分かります。
OS で「動きを減らす」設定にしている人には自動再生をやめ、5秒を超えて動くものには止める手段を付けます。 MDN は prefers-reduced-motion を「ユーザーが余計な動きを最少化するよう要求したことを検出する」メディア特性と説明しています。lottie-web はこの設定を自動では見ないため、JavaScript で分岐します。
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)');
const anim = lottie.loadAnimation({
container: document.getElementById('lottie'),
renderer: 'svg', loop: true,
autoplay: !reduce.matches, // 動きを減らす設定なら自動再生しない
path: 'demo.json'
});
anim.addEventListener('DOMLoaded', () => {
if (reduce.matches) anim.goToAndStop(anim.totalFrames - 1, true); // 完成形の絵で止める
});
reduce.addEventListener('change', (e) => e.matches ? anim.pause() : anim.play());
// 一時停止ボタン
const btn = document.getElementById('toggle');
btn.addEventListener('click', () => {
anim.isPaused ? anim.play() : anim.pause();
btn.setAttribute('aria-pressed', String(anim.isPaused));
});
Chromium の「動きを減らす」設定を Playwright で切り替えて確かめると、通常の設定では自動で再生が進み(300ミリ秒で 44.5→53.5 フレーム)、reduce では最後のフレーム(59)で止まったままでした。一時停止ボタンを押すと isPaused が true、aria-pressed が "true" になりました。
WCAG 2.2 の達成基準 2.2.2(レベル A)は、自動で始まり、5秒より長く続き、他の内容と並んで表示される動きには、一時停止・停止・非表示にする仕組みを求めています。読み込み中の表示のように処理が終われば消えるもの以外は、ボタンを付けておくのが確実です。
- 1prefers-reduced-motion で自動再生を止める止めるときは最初ではなく、意味の伝わるフレーム(完成形)を見せる
- 25秒を超えて動くなら一時停止ボタンを付けるループ再生の背景・説明イラストが対象になりやすい
- 3意味のある動きには代わりの文字を付けるlottie-web の SVG には role も代替テキストも付かなかった。container に role="img" と aria-label を付ける
- 4飾りだけの動きは読み上げから外すcontainer に aria-hidden="true" を付ける
- 5激しい点滅を作らない1秒に3回を超える点滅は WCAG 2.3.1 の対象になる
CSS アニメーション側での prefers-reduced-motion の書き方は、関連記事「CSS アニメーション|transitionとkeyframesの違いと実用20選」で扱っています。
Lottieのよくある不具合:表示されない・重い・テキストが崩れる
この節では、Lottie が思ったとおりに出ないときに、症状から原因を絞る方法が分かります。
まずブラウザの開発者ツールでコンソールとネットワークを見て、JSON が 200 で届いているかを確かめます。 手元でわざと起こした不具合と、そのときの原文です。
| 症状 | 原因 | 出た原文・状態 | 直し方 |
|---|---|---|---|
| 何も表示されない | path の JSON が無い(404) | Failed to load resource: the server responded with a status of 404 (File not found)。data_failed イベント | URL を直す。data_failed で代わりの画像を出す |
| 何も表示されない | JSON が途中で切れている | Uncaught TypeError: Cannot read properties of null (reading '__complete') | JSON を構文チェックする。書き出し直す |
| 何も表示されない | file:// で開いた | ... has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes ... | HTTP サーバーから開く。animationData で渡す |
| 何も表示されない | lottie-web を読み込む前に呼んだ | Uncaught ReferenceError: lottie is not defined | script の順番を直す。npm なら import する |
| エラーも出ず表示されない | container が null(id の書き間違い・要素より前で実行) | コンソールに何も出ない。DOMLoaded も起きない | 要素の後ろで実行するか DOMContentLoaded を待つ |
| 一部の動きが止まっている | lottie_light で Expressions を使った JSON を再生 | エラーは出ず、式で動く部分だけが止まる | 全部入りの lottie.min.js に替える |
| 文字の形や幅が違う | JSON が指定するフォントが閲覧環境に無い | 明朝系に置き換わり、幅が 258px → 248px に変わった | フォントを読み込む。文字をシェイプに変換して書き出す |
| .lottie が出ない | ZIP の中の置き場所が仕様と違う | load も loadError も起きない | 2.0 なら a/ に置く |
テキストが崩れる理由
テキストレイヤーには文字の形ではなく、フォント名(fFamily)と文字列が入っています。手書きの JSON で、存在しないフォント名「BrandFont」を指定すると、Chromium は既定のセリフ体で描き、文字列の幅は 248px でした。同じ JSON のフォント名を、この環境に入っている「Noto Sans CJK JP」に変えると 258px です。lottie-web は1文字ずつ text 要素を並べる(この例では12個)ため、フォントが替わると文字の間隔や行の折り返しもずれます。
1フォントを読み込む
Web フォントとして CSS で読み込み、JSON の fFamily と同じ名前にそろえる。
2文字を図形にする
文字を変えない見出しなら、After Effects 側でシェイプに変換して書き出すと閲覧環境に左右されない。
3文字は HTML で重ねる
翻訳や読み上げが要る文は、Lottie の外の HTML に置く。検索エンジンにも読まれる。
重いときに見る順番
- 1画面の外では止めるIntersectionObserver で見えているものだけ play() する。5個を縦に並べた検証で、最初は上の2個だけが動き、下へスクロールすると一番下の1個だけが動いた
- 2使い終わったら destroy() するSPA の画面切り替えで残りやすい。20個再生で JS ヒープは 7〜8MB だった
- 3同時に動かす数を減らす20個でメインスレッドを 8〜29% 使った。飾りの動きは1画面に1〜2個に絞る
- 4レンダラーを対象の端末で比べるこの環境では svg が canvas より軽かった。GPU のある端末では逆になることもある
- 5JSON の中を減らすREADME は、大きな図形で小さな部分をマスクしない・ノードを増やしすぎないことを勧めている。マスクとエフェクトは負荷が大きい
const io = new IntersectionObserver((entries) => {
for (const e of entries) {
const anim = e.target._anim;
e.isIntersecting ? anim.play() : anim.pause();
}
});
for (const el of document.querySelectorAll('.lottie')) {
el._anim = lottie.loadAnimation({ container: el, renderer: 'svg', loop: true, autoplay: false, path: 'demo.json' });
io.observe(el);
}
Lottie・GIF・動画・CSS・SVGの使い分け(判断表)
この節では、作りたい動きに対して、どの形式を選べばよいかが分かります。
単純な移動・回転・色の変化なら CSS、イラストのような複雑な動きを軽く・拡大しても綺麗に出したいなら Lottie、写真や実写なら動画です。 実測と仕様を合わせて判断表にしました。
| 作りたいもの | 第一候補 | 理由 |
|---|---|---|
| ボタンの押下・ホバー・開閉 | CSS | ライブラリ不要。容量 314 バイト(gzip)で済んだ |
| 読み込み中・完了・空の状態のイラスト | Lottie | デザイナーの動きをそのまま使え、拡大してもにじまない |
| 操作に合わせて途中で止める・区間を変える | Lottie | playSegments・goToAndStop でフレーム単位に操作できる |
| アイコン1つの単純な動き | SVG(SMIL か CSS) | 1ファイルで完結。img で読み込める |
| 写真・実写・グラデーションの多い映像 | 動画(MP4・WebM) | ベクターでは表せない。今回の例でも GIF の約5分の1 |
| メール・チャットなど JS が動かない場所 | GIF(か動画) | Lottie は再生にプログラムが要る |
| 複数の動き・画像・テーマを1つで配る | dotLottie | ZIP 1つにまとまる。wasm の取得を考えておく |
- 1CSS で書けるかtransform・opacity・色だけで済むなら CSS。いちばん軽い
- 2図形の動きか、映像か写真や実写なら動画。図形・イラストなら次へ
- 3JavaScript が動く場所か動かないなら GIF か動画。動くなら次へ
- 4デザイナーが After Effects などで作るか作るなら Lottie。手で書ける単純な動きなら SVG
- 5ページに同時に何個出すか多いなら canvas レンダラー・画面外での停止を組み合わせる
画像としての SVG の扱いは関連記事「SVGファイルとは|PNGとの違い・開き方・作り方を実測で解説」、静止画やアニメーション画像の圧縮は関連記事「WebP・HEICとは|JPG・PNGへの変換と画像圧縮を実測で解説」で扱っています。
よくある質問
Q. Lottie とは何ですか? A. 図形の動きを JSON で表したベクターアニメーションの形式です。lottie-web などのプレイヤーが、その場で SVG や Canvas に描きます。読み方は「ロッティー」です。
Q. Lottie は無料で使えますか? A. lottie-web は MIT ライセンスのオープンソースで無料です。LottieFiles の無料の公開素材は Lottie Simple License で、商用利用もできます。有料素材や他サイトの素材は、それぞれの条件を確かめます。
Q. Lottie は GIF より軽いですか? A. データだけなら大幅に軽く、この記事の例で JSON 1,429 バイトに対して GIF 69,873 バイトでした。ただし再生に lottie-web(gzip で 46〜76KB)が要るため、ページに1つだけ置くなら合計では大差がなくなることもあります。
Q. After Effects が無くても Lottie を作れますか? A. 作れます。単純な図形なら JSON を手で書けますし、LottieFiles は Figma からの書き出しや SVG からの変換、ブラウザ上のエディターを案内しています。
Q. lottie-web の renderer は svg と canvas のどちらがよいですか? A. まず svg を選びます。GPU の無いこの検証環境では、20個同時の再生でも svg のほうが canvas よりメインスレッドの負荷が小さく(8.3% と 22.3%)なりました。端末によって差が変わるため、多数を同時に出すときは対象の端末で両方を測ります。
Q. 一度だけ再生して止めるには?
A. loop: false にします。止まったときに処理をしたいなら complete イベントを使います。
Q. 途中の一部分だけを繰り返したいときは?
A. playSegments([開始, 終了], true) と loop: true を組み合わせます。全体に戻すときは resetSegments(true) を呼びます。
Q. Lottie の色をプログラムから変えられますか?
A. JSON の c(0〜1 の RGBA)を書き換えてから animationData で渡すのが確実です。dotLottie にはテーマの仕組みがあります。
Q. スマホアプリでも同じファイルを使えますか? A. Airbnb の Lottie は Android・iOS・Web・Windows 向けのライブラリがあり、同じ JSON を使えます。ただし対応している機能はライブラリごとに違うため、各プラットフォームで再生して確かめます。
Q. .lottie と .json はどちらで配ればよいですか? A. 単純な動き1つなら、gzip 配信の JSON のほうが小さくなりました。画像を含む・複数の動きをまとめる・テーマを切り替えるなら .lottie が向きます。
Q. Lottie は検索エンジンに読まれますか? A. 動きの中の文字は、ページの本文としては扱いにくい形です。伝えたい文は HTML の文字として別に置き、Lottie は飾りか補足として使います。
まとめ
- Lottie は図形の動きを JSON で表したベクターアニメーションの形式で、仕様は LAC(Linux Foundation がホスト)が策定している。
- JSON は fr・op・w・h → layers(ty で種類)→ ks(動き)と shapes(形)の順に読む。キーフレームは t と s、イージングは i と o。
- Web では lottie-web の loadAnimation に container と path を渡す。goToAndStop は第2引数を省くとミリ秒、playSegments は resetSegments まで残る。
- 同じ動きで、JSON は GIF の約49分の1。ただしライブラリ(gzip 46〜76KB)が要り、メインスレッドは GIF・CSS・動画より多く使った。
- 単純な動きは CSS、イラスト的な動きは Lottie、映像は動画。prefers-reduced-motion と一時停止ボタンを組み込む。
参考・出典
確認日はいずれも 2026年10月29日です。
- Lottie Animation Community「Lottie Animation Community」:https://lottie.github.io/
- Lottie Animation Community「Lottie Specification 1.0.1」(Composition・Layers・Shapes・Properties):https://lottie.github.io/lottie-spec/1.0.1/
- Airbnb「Lottie Docs」:https://lottie.airbnb.tech/
- airbnb/lottie-web README(npm パッケージ lottie-web 5.13.0 に同梱):https://github.com/airbnb/lottie-web
- LottieFiles「Lottieアニメーションとは?」:https://lottiefiles.com/jp/what-is-lottie
- LottieFiles「Lottie Simple License (FL 9.13.21)」:https://lottiefiles.com/page/license
- dotLottie「dotLottie 2.0 Specification」:https://dotlottie.io/spec/2.0/
- LottieFiles「dotlottie-web」README(npm パッケージ @lottiefiles/dotlottie-web 0.82.0 に同梱):https://github.com/LottieFiles/dotlottie-web
- lottie-react README(npm パッケージ lottie-react 3.1.2 に同梱):https://github.com/Gamote/lottie-react
- MDN「prefers-reduced-motion」:https://developer.mozilla.org/ja/docs/Web/CSS/@media/prefers-reduced-motion
- W3C「Understanding Success Criterion 2.2.2: Pause, Stop, Hide」:https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Lottieとは?使い方とJSONの読み方、GIF・動画との容量比較」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。