SolidJS のアニメーション比較:Motion One vs Popmotion vs CSS Transitions
SolidJS で Web アプリケーションを開発する際、UI にアニメーションを追加することでユーザー体験を大きく向上させることができます。しかし、アニメーションライブラリやアプローチの選択肢は多く、どれを選べば良いか迷ってしまうことも多いでしょう。
本記事では、SolidJS で利用できる代表的な 3 つのアニメーション手法(Motion One、Popmotion、CSS Transitions)を詳しく比較します。それぞれの特徴、パフォーマンス、実装方法を具体的なコード例とともに解説し、プロジェクトに最適な選択ができるようサポートいたしますね。
背景
SolidJS におけるアニメーションの重要性
SolidJS は、リアクティブな状態管理と高速なレンダリングパフォーマンスを特徴とするフレームワークです。仮想 DOM を使わず、細かい粒度でのリアクティビティを実現しているため、アニメーション処理においても非常に高いパフォーマンスを発揮できます。
UI アニメーションは単なる装飾ではなく、以下のような重要な役割を果たします。
- フィードバックの提供: ユーザーの操作に対する視覚的な応答
- 状態遷移の明示: データや UI の変化を滑らかに表現
- 注目の誘導: 重要な要素やアクションへユーザーの視線を導く
- ブランド体験の向上: 独自のモーションデザインでアイデンティティを表現
3 つのアニメーション手法の概要
SolidJS でアニメーションを実装する際、主に 3 つのアプローチから選択することになります。
以下の図で、各アプローチの基本的な位置づけを理解しましょう。
mermaidflowchart TB
approach["アニメーション<br/>アプローチ"]
css["CSS Transitions"]
jslib["JavaScript<br/>ライブラリ"]
motion["Motion One"]
pop["Popmotion"]
approach --> css
approach --> jslib
jslib --> motion
jslib --> pop
css -.->|軽量・シンプル| simple["シンプルな<br/>アニメーション"]
motion -.->|バランス重視| medium["中規模<br/>アニメーション"]
pop -.->|高度な制御| complex["複雑な<br/>アニメーション"]
この図から、CSS Transitions は軽量でシンプルなアニメーション、Motion One はバランスの取れた中規模のアニメーション、Popmotion は高度な制御が必要な複雑なアニメーションに適していることがわかります。
| # | 手法 | 特徴 | 適用場面 |
|---|---|---|---|
| 1 | CSS Transitions | ブラウザネイティブ、軽量 | ホバー効果、シンプルな状態遷移 |
| 2 | Motion One | 軽量 JavaScript ライブラリ、Web Animations API | 中規模のインタラクティブアニメーション |
| 3 | Popmotion | 高機能、物理演算サポート | 複雑なジェスチャー、物理ベースのアニメーション |
それぞれに長所と短所があり、プロジェクトの要件に応じて使い分けることが重要です。
なぜアニメーション手法の選択が重要なのか
適切なアニメーション手法を選択することは、以下の理由から非常に重要です。
パフォーマンスへの影響は無視できません。不適切な実装は、特にモバイル端末でフレームレートの低下やバッテリー消費の増加を引き起こします。
バンドルサイズも考慮すべき要素です。大規模なライブラリを導入すると、初期ロード時間が延びてしまい、ユーザー体験を損なう可能性があります。
開発効率とメンテナンス性も見逃せません。シンプルなアニメーションに複雑なライブラリを使うのは過剰ですし、逆に複雑なアニメーションを CSS Transitions だけで実装しようとすると、コードが肥大化してしまいます。
課題
アニメーションライブラリ選択の難しさ
SolidJS でアニメーションを実装しようとすると、開発者は以下のような課題に直面します。
情報の断片化が第一の課題です。React や Vue と比較して、SolidJS 特化のアニメーション情報は少なく、各ライブラリの比較記事も限られています。
パフォーマンスとバンドルサイズのトレードオフも悩ましい問題です。高機能なライブラリほどバンドルサイズが大きくなり、初期ロード時間に影響します。
以下の図で、各手法が抱える課題を整理してみましょう。
mermaidflowchart TD
start["アニメーション<br/>実装の課題"]
start --> info["情報不足"]
start --> perf["パフォーマンス<br/>懸念"]
start --> bundle["バンドルサイズ"]
start --> learn["学習コスト"]
info --> react["Reactの情報が<br/>多い"]
info --> solid["SolidJS特化<br/>情報が少ない"]
perf --> fps["フレームレート<br/>低下"]
perf --> mobile["モバイル<br/>パフォーマンス"]
bundle --> init["初期ロード<br/>遅延"]
bundle --> choice["ライブラリ<br/>選択"]
learn --> api["API理解"]
learn --> best["ベスト<br/>プラクティス"]
この図から、アニメーション実装には多角的な課題があることが理解できます。
具体的な技術的課題
開発現場では、以下のような具体的な疑問が生じます。
| # | 課題 | 詳細 |
|---|---|---|
| 1 | パフォーマンス比較 | 60fps を維持できるのはどれか |
| 2 | バンドルサイズ影響 | 各手法のファイルサイズ差 |
| 3 | 学習曲線 | 習得にかかる時間と難易度 |
| 4 | 機能の制約 | 実現できないアニメーションはあるか |
| 5 | SolidJS との親和性 | リアクティブシステムとの統合 |
CSS Transitions の限界として、複雑なシーケンスアニメーションや、JavaScript の値に基づく動的なアニメーションの実装が困難という点があります。
Motion One の情報不足も課題です。比較的新しいライブラリのため、SolidJS での実装例やベストプラクティスが十分に確立されていません。
Popmotion の複雑さは、高機能である反面、学習コストが高く、シンプルなアニメーションには過剰になりがちです。
プロジェクト要件との適合性
プロジェクトによって、アニメーションに求められる要件は大きく異なります。
EC サイトでは、商品画像のホバー効果やカートへの追加アニメーションなど、シンプルで高速なアニメーションが求められます。この場合、バンドルサイズを最小限に抑えることが重要でしょう。
ゲームやインタラクティブな Web アプリでは、ドラッグ&ドロップ、物理演算、複雑なジェスチャー認識など、高度なアニメーション機能が必要になります。
コーポレートサイトでは、スクロールアニメーションやパララックス効果など、視覚的な印象を重視したアニメーションが中心となります。
このように、プロジェクトの性質に応じて最適な選択肢は変わってくるのです。
解決策
3 つのアニメーション手法の詳細比較
それぞれのアニメーション手法について、特徴、メリット、デメリットを詳しく見ていきましょう。適切な選択をするために、各手法の本質を理解することが重要です。
以下の図で、3 つの手法の関係性と選択基準を整理します。
mermaidflowchart LR
requirement["要件分析"]
simple["シンプルな<br/>アニメーション"]
medium["中規模<br/>アニメーション"]
complex["複雡な<br/>アニメーション"]
css["CSS Transitions<br/>★軽量<br/>★シンプル"]
motion["Motion One<br/>★バランス<br/>★WAAPI"]
pop["Popmotion<br/>★高機能<br/>★物理演算"]
requirement --> simple
requirement --> medium
requirement --> complex
simple --> css
medium --> motion
complex --> pop
css -.->|不足| motion
motion -.->|不足| pop
この図から、要件の複雑さに応じて段階的にアニメーション手法を選択する流れが理解できます。
CSS Transitions:ブラウザネイティブの力
CSS Transitions は、ブラウザに組み込まれたアニメーション機能です。JavaScript のバンドルサイズに一切影響を与えず、最も軽量な選択肢となります。
メリットとして、以下の点が挙げられます。
- ゼロバンドルサイズ(追加の JavaScript ライブラリ不要)
- GPU アクセラレーションによる高速描画
- ブラウザ最適化による安定したパフォーマンス
- シンプルで直感的な実装
デメリットも理解しておく必要があります。
- 複雑なシーケンスアニメーションの実装が困難
- JavaScript との統合が限定的
- イージング関数の選択肢が少ない
- アニメーションの動的な制御に制約がある
| # | 項目 | 評価 | 補足 |
|---|---|---|---|
| 1 | バンドルサイズ | ★★★★★ | 0KB(追加なし) |
| 2 | パフォーマンス | ★★★★★ | GPU アクセラレーション |
| 3 | 学習コスト | ★★★★★ | CSS 知識のみ |
| 4 | 機能性 | ★★☆☆☆ | シンプルな遷移のみ |
| 5 | SolidJS 統合 | ★★★☆☆ | クラス切り替えで対応 |
Motion One:モダンで軽量な JavaScript ライブラリ
Motion One は、Web Animations API(WAAPI)をベースにした軽量なアニメーションライブラリです。わずか 5KB 程度のバンドルサイズで、強力なアニメーション機能を提供します。
メリットは以下の通りです。
- 非常に軽量(約 5KB gzipped)
- Web Animations API による高パフォーマンス
- シンプルで直感的な API
- タイムラインとシーケンスアニメーションのサポート
- SolidJS のリアクティビティとの良好な統合
デメリットも確認しておきましょう。
- Popmotion と比較して機能が限定的
- 物理演算やスプリングアニメーションが基本的でない
- ドラッグ&ドロップなどのジェスチャーは別途実装が必要
| # | 項目 | 評価 | 補足 |
|---|---|---|---|
| 1 | バンドルサイズ | ★★★★☆ | 約 5KB gzipped |
| 2 | パフォーマンス | ★★★★★ | WAAPI 活用 |
| 3 | 学習コスト | ★★★★☆ | シンプルな API |
| 4 | 機能性 | ★★★★☆ | 中規模アニメーション対応 |
| 5 | SolidJS 統合 | ★★★★★ | 優れた統合性 |
Popmotion:高機能な物理演算ライブラリ
Popmotion は、物理演算に基づいた自然なアニメーションを実現する、フル機能のアニメーションライブラリです。Framer Motion の基盤としても使われています。
メリットは非常に魅力的です。
- 物理演算ベースの自然なアニメーション
- スプリング、慣性、減衰などの高度なイージング
- ドラッグ、スワイプなどのジェスチャー認識
- 詳細なアニメーション制御が可能
- 複雑なインタラクションの実装に最適
デメリットも考慮が必要です。
- 比較的大きなバンドルサイズ(約 11KB gzipped)
- 学習コストが高め
- シンプルなアニメーションには過剰
| # | 項目 | 評価 | 補足 |
|---|---|---|---|
| 1 | バンドルサイズ | ★★★☆☆ | 約 11KB gzipped |
| 2 | パフォーマンス | ★★★★☆ | 最適化された物理演算 |
| 3 | 学習コスト | ★★☆☆☆ | API 習得に時間要 |
| 4 | 機能性 | ★★★★★ | 最も高機能 |
| 5 | SolidJS 統合 | ★★★★☆ | 手動統合が必要 |
選択基準とフローチャート
プロジェクトに最適なアニメーション手法を選ぶため、以下の基準を参考にしてください。
CSS Transitions を選ぶべき場合
- ホバー効果、フェードイン/アウトなどのシンプルなアニメーション
- バンドルサイズを最小限に抑えたい
- ブラウザのネイティブパフォーマンスを最大限活用したい
Motion One を選ぶべき場合
- タイムラインベースの中規模アニメーション
- 軽量ながら柔軟なアニメーション制御が必要
- SolidJS のリアクティビティと統合したい
- Web 標準(WAAPI)に準拠したい
Popmotion を選ぶべき場合
- 物理演算ベースの自然なアニメーション
- ドラッグ&ドロップ、スワイプなどのジェスチャー
- 複雑なインタラクティブアニメーション
- バンドルサイズよりも機能性を優先
具体例
プロジェクトセットアップ
まず、SolidJS プロジェクトを作成し、それぞれのアニメーションライブラリをインストールします。
SolidJS プロジェクトの作成
以下のコマンドで SolidJS プロジェクトを初期化します。
bashyarn create vite solidjs-animation-demo --template solid-ts
cd solidjs-animation-demo
依存パッケージのインストール
3 つのアニメーション手法を試すため、必要なパッケージをインストールしましょう。
bashyarn add motion popmotion
yarn add -D @types/node
これで、Motion One と Popmotion が利用可能になります。CSS Transitions は追加のパッケージ不要です。
実装例 1:CSS Transitions によるボタンアニメーション
最もシンプルなアプローチとして、CSS Transitions でボタンのホバー効果を実装します。
コンポーネントの作成
まず、ボタンコンポーネントを作成しましょう。
typescript// src/components/ButtonCSS.tsx
import { Component } from 'solid-js';
import './ButtonCSS.css';
const ButtonCSS: Component = () => {
return (
<button class='css-button'>ホバーしてください</button>
);
};
export default ButtonCSS;
このコンポーネントは、CSS クラスを適用したシンプルなボタンです。
CSS スタイルの定義
次に、トランジションアニメーションを定義します。
css/* src/components/ButtonCSS.css */
.css-button {
padding: 12px 24px;
font-size: 16px;
font-weight: 600;
background: linear-gradient(
135deg,
#667eea 0%,
#764ba2 100%
);
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
/* トランジションの設定 */
transition: transform 0.3s ease, box-shadow 0.3s ease;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
transitionプロパティで、transform と box-shadow に 0.3 秒のイージングアニメーションを適用しています。
ホバー状態の定義
ホバー時の状態を定義します。
css/* src/components/ButtonCSS.css(続き) */
.css-button:hover {
/* ボタンを少し上に移動 */
transform: translateY(-2px);
/* 影を濃くして立体感を強調 */
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.2);
}
.css-button:active {
/* クリック時は元の位置に */
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
ホバー時にボタンが浮き上がり、クリック時に押し込まれる効果を実現しています。
CSS Transitions のポイント
- ブラウザネイティブの機能で追加コストゼロ
- GPU アクセラレーション対象のプロパティ(transform、opacity)を使用
- シンプルで保守性が高い
- モバイル端末でも安定したパフォーマンス
実装例 2:Motion One によるカードアニメーション
Motion One を使って、カードの登場アニメーションとインタラクティブな効果を実装します。
Motion One のインポート
Motion One の主要な関数をインポートします。
typescript// src/components/CardMotion.tsx
import { Component, onMount } from 'solid-js';
import { animate, spring } from 'motion';
import './CardMotion.css';
animate関数で基本的なアニメーション、spring関数で物理ベースのスプリングアニメーションを実現できます。
コンポーネントの定義
カードコンポーネントを定義します。
typescript// src/components/CardMotion.tsx(続き)
const CardMotion: Component = () => {
let cardRef: HTMLDivElement | undefined;
onMount(() => {
if (!cardRef) return;
// 登場アニメーション
animate(
cardRef,
{
opacity: [0, 1],
y: [50, 0],
},
{
duration: 0.6,
easing: spring({ stiffness: 200, damping: 20 }),
}
);
});
return (
<div ref={cardRef} class='motion-card'>
<h3>Motion One カード</h3>
<p>スムーズな登場アニメーション</p>
</div>
);
};
onMountフック内でアニメーションを実行し、不透明度 0 から 1、Y 座標 50px から 0px へのスプリングアニメーションを実現しています。
ホバーアニメーションの追加
マウスホバー時のアニメーションを追加しましょう。
typescript// src/components/CardMotion.tsx(続き、returnの前に追加)
const handleMouseEnter = () => {
if (!cardRef) return;
animate(
cardRef,
{ scale: 1.05 },
{ duration: 0.3, easing: 'ease-out' }
);
};
const handleMouseLeave = () => {
if (!cardRef) return;
animate(
cardRef,
{ scale: 1 },
{ duration: 0.3, easing: 'ease-out' }
);
};
ホバー時にカードが 1.05 倍に拡大し、離れると元のサイズに戻ります。
イベントハンドラの適用
コンポーネントの return 部分を更新します。
typescript// src/components/CardMotion.tsx(return部分を更新)
return (
<div
ref={cardRef}
class='motion-card'
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<h3>Motion One カード</h3>
<p>スムーズな登場アニメーション</p>
</div>
);
スタイルの定義
基本的なスタイルを定義します。
css/* src/components/CardMotion.css */
.motion-card {
width: 300px;
padding: 24px;
background: white;
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
cursor: pointer;
/* 初期状態は透明(JSで制御) */
opacity: 0;
}
.motion-card h3 {
margin: 0 0 12px 0;
font-size: 20px;
color: #333;
}
.motion-card p {
margin: 0;
color: #666;
line-height: 1.5;
}
Motion One のポイント
- わずか 5KB 程度の軽量ライブラリ
- Web Animations API を活用した高パフォーマンス
- SolidJS のリアクティビティと自然に統合
- スプリングアニメーションで物理的な動きを実現
- タイムラインやシーケンスアニメーションも可能
実装例 3:Popmotion によるドラッグ可能な要素
Popmotion を使って、物理演算ベースのドラッグ&ドロップを実装します。
Popmotion のインポート
必要な関数をインポートします。
typescript// src/components/DraggablePopmotion.tsx
import { Component, onMount, onCleanup } from 'solid-js';
import { animate, inertia } from 'popmotion';
import './DraggablePopmotion.css';
animateで基本アニメーション、inertiaで慣性を持った自然な動きを実現します。
コンポーネントの状態管理
ドラッグ状態を管理するコンポーネントを作成します。
typescript// src/components/DraggablePopmotion.tsx(続き)
const DraggablePopmotion: Component = () => {
let boxRef: HTMLDivElement | undefined;
let isDragging = false;
let startX = 0;
let startY = 0;
let currentX = 0;
let currentY = 0;
return (
<div class='draggable-container'>
<div ref={boxRef} class='draggable-box'>
ドラッグしてください
</div>
</div>
);
};
ドラッグの状態を追跡するための変数を定義しています。
マウスダウンイベントの処理
ドラッグ開始を検知します。
typescript// src/components/DraggablePopmotion.tsx(onMount前に追加)
const handleMouseDown = (e: MouseEvent) => {
if (!boxRef) return;
isDragging = true;
startX = e.clientX - currentX;
startY = e.clientY - currentY;
// ドラッグ中はカーソルを変更
boxRef.style.cursor = 'grabbing';
};
マウスダウン時に、開始位置を記録し、ドラッグ状態を true に設定します。
マウス移動イベントの処理
ドラッグ中の要素移動を処理します。
typescript// src/components/DraggablePopmotion.tsx(続き)
const handleMouseMove = (e: MouseEvent) => {
if (!isDragging || !boxRef) return;
e.preventDefault();
currentX = e.clientX - startX;
currentY = e.clientY - startY;
// 即座に位置を更新
boxRef.style.transform = `translate(${currentX}px, ${currentY}px)`;
};
マウスの移動に合わせて、要素の位置をリアルタイムで更新します。
マウスアップイベントの処理
ドラッグ終了時に慣性アニメーションを適用します。
typescript// src/components/DraggablePopmotion.tsx(続き)
const handleMouseUp = (e: MouseEvent) => {
if (!isDragging || !boxRef) return;
isDragging = false;
boxRef.style.cursor = 'grab';
// 慣性アニメーションを適用
const velocityX = e.movementX;
const velocityY = e.movementY;
inertia({
from: currentX,
velocity: velocityX * 10,
power: 0.8,
timeConstant: 300,
modifyTarget: (target) => Math.round(target),
}).start({
update: (x) => {
currentX = x;
if (boxRef) {
boxRef.style.transform = `translate(${currentX}px, ${currentY}px)`;
}
},
});
inertia({
from: currentY,
velocity: velocityY * 10,
power: 0.8,
timeConstant: 300,
modifyTarget: (target) => Math.round(target),
}).start({
update: (y) => {
currentY = y;
if (boxRef) {
boxRef.style.transform = `translate(${currentX}px, ${currentY}px)`;
}
},
});
};
ドラッグ終了時に、マウスの速度を検知して慣性アニメーションを適用し、自然な減速を実現しています。
イベントリスナーの登録
onMount でイベントリスナーを登録します。
typescript// src/components/DraggablePopmotion.tsx(続き)
onMount(() => {
if (!boxRef) return;
boxRef.addEventListener('mousedown', handleMouseDown);
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
});
onCleanup(() => {
if (!boxRef) return;
boxRef.removeEventListener('mousedown', handleMouseDown);
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseUp);
});
コンポーネントのマウント時にイベントを登録し、クリーンアップ時に削除しています。
スタイルの定義
ドラッグ可能な要素のスタイルを定義します。
css/* src/components/DraggablePopmotion.css */
.draggable-container {
width: 100%;
height: 400px;
background: #f5f5f5;
border-radius: 12px;
position: relative;
overflow: hidden;
}
.draggable-box {
width: 120px;
height: 120px;
background: linear-gradient(
135deg,
#f093fb 0%,
#f5576c 100%
);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: 600;
cursor: grab;
user-select: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.draggable-box:active {
cursor: grabbing;
}
Popmotion のポイント
- 物理演算ベースの自然な慣性アニメーション
- ドラッグ&ドロップの細かい制御が可能
- スプリング、減衰、慣性など高度な物理シミュレーション
- 複雑なジェスチャーやインタラクションに最適
- より高度な制御が必要な場合の最良の選択肢
実装例 4:3 つの手法を比較するデモページ
3 つのアニメーション手法を一つのページで比較できるデモを作成しましょう。
メインアプリケーションの構成
各コンポーネントをインポートして配置します。
typescript// src/App.tsx
import { Component } from 'solid-js';
import ButtonCSS from './components/ButtonCSS';
import CardMotion from './components/CardMotion';
import DraggablePopmotion from './components/DraggablePopmotion';
import './App.css';
const App: Component = () => {
return (
<div class='app'>
<header class='app-header'>
<h1>SolidJS アニメーション比較デモ</h1>
<p>CSS Transitions vs Motion One vs Popmotion</p>
</header>
<main class='app-main'>
{/* セクション1:CSS Transitions */}
<section class='demo-section'>
<h2>CSS Transitions</h2>
<p>
ブラウザネイティブのシンプルなアニメーション
</p>
<div class='demo-content'>
<ButtonCSS />
</div>
<div class='demo-info'>
<strong>バンドルサイズ:</strong> 0KB(追加なし)
</div>
</section>
{/* セクション2:Motion One */}
<section class='demo-section'>
<h2>Motion One</h2>
<p>軽量で高機能なJavaScriptライブラリ</p>
<div class='demo-content'>
<CardMotion />
</div>
<div class='demo-info'>
<strong>バンドルサイズ:</strong> 約5KB gzipped
</div>
</section>
{/* セクション3:Popmotion */}
<section class='demo-section'>
<h2>Popmotion</h2>
<p>物理演算ベースの高度なアニメーション</p>
<div class='demo-content'>
<DraggablePopmotion />
</div>
<div class='demo-info'>
<strong>バンドルサイズ:</strong> 約11KB gzipped
</div>
</section>
</main>
</div>
);
};
export default App;
3 つのセクションに分けて、それぞれのアニメーション手法を配置しています。
アプリケーションスタイルの定義
全体のレイアウトを整えます。
css/* src/App.css */
.app {
min-height: 100vh;
background: linear-gradient(
to bottom right,
#f8f9fa,
#e9ecef
);
padding: 40px 20px;
}
.app-header {
text-align: center;
margin-bottom: 60px;
}
.app-header h1 {
font-size: 36px;
color: #333;
margin: 0 0 12px 0;
}
.app-header p {
font-size: 18px;
color: #666;
margin: 0;
}
セクションスタイルの定義
各デモセクションのスタイルを定義します。
css/* src/App.css(続き) */
.app-main {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax(350px, 1fr)
);
gap: 40px;
}
.demo-section {
background: white;
border-radius: 16px;
padding: 32px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.demo-section h2 {
font-size: 24px;
color: #333;
margin: 0 0 8px 0;
}
.demo-section p {
color: #666;
margin: 0 0 24px 0;
}
.demo-content {
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 24px;
}
.demo-info {
padding: 16px;
background: #f8f9fa;
border-radius: 8px;
font-size: 14px;
color: #666;
}
グリッドレイアウトで各セクションを配置し、統一感のあるデザインを実現しています。
パフォーマンス比較の実装
各アニメーション手法のパフォーマンスを計測する機能を追加しましょう。
パフォーマンス計測コンポーネント
フレームレートを計測するコンポーネントを作成します。
typescript// src/components/PerformanceMonitor.tsx
import {
Component,
createSignal,
onMount,
onCleanup,
} from 'solid-js';
import './PerformanceMonitor.css';
const PerformanceMonitor: Component = () => {
const [fps, setFps] = createSignal(0);
let frameCount = 0;
let lastTime = performance.now();
let animationId: number;
const measureFPS = () => {
frameCount++;
const currentTime = performance.now();
if (currentTime >= lastTime + 1000) {
setFps(
Math.round(
(frameCount * 1000) / (currentTime - lastTime)
)
);
frameCount = 0;
lastTime = currentTime;
}
animationId = requestAnimationFrame(measureFPS);
};
onMount(() => {
animationId = requestAnimationFrame(measureFPS);
});
onCleanup(() => {
cancelAnimationFrame(animationId);
});
return (
<div class='performance-monitor'>
<span class='fps-label'>FPS:</span>
<span class='fps-value'>{fps()}</span>
</div>
);
};
export default PerformanceMonitor;
requestAnimationFrame を使って、リアルタイムでフレームレートを計測しています。
パフォーマンスモニターのスタイル
計測結果を見やすく表示します。
css/* src/components/PerformanceMonitor.css */
.performance-monitor {
position: fixed;
top: 20px;
right: 20px;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 12px 20px;
border-radius: 8px;
font-family: monospace;
font-size: 16px;
z-index: 1000;
}
.fps-label {
margin-right: 8px;
color: #aaa;
}
.fps-value {
font-weight: bold;
color: #4ade80;
}
画面右上に固定表示し、現在の FPS 値を確認できます。
図で理解できる要点
3 つのアニメーション手法の選択基準
- シンプルな UI 遷移には CSS Transitions が最適
- バランスの取れた実装には Motion One を選択
- 高度なインタラクションには Popmotion が必要
実装の複雑さと機能性のトレードオフ
- CSS Transitions は最もシンプルだが機能が限定的
- Motion One は軽量で多くのケースに対応可能
- Popmotion は学習コストが高いが最も高機能
まとめ
SolidJS で利用できる 3 つのアニメーション手法(CSS Transitions、Motion One、Popmotion)について、詳しく比較してきました。それぞれの特徴を理解し、プロジェクトに最適な選択をすることが重要です。
各手法の適用シーン
CSS Transitions は以下のケースに最適です
- ホバー効果、フォーカス状態などのシンプルな UI 変化
- バンドルサイズを最小限に抑えたいプロジェクト
- ブラウザのネイティブパフォーマンスを活用したい場合
- 保守性とシンプルさを重視する場合
Motion One は以下のケースに最適です
- 登場アニメーション、スクロールアニメーションなどの中規模アニメーション
- 軽量ながら柔軟な制御が必要な場合
- タイムラインやシーケンスアニメーションを実装したい場合
- SolidJS のリアクティビティと統合したい場合
Popmotion は以下のケースに最適です
- ドラッグ&ドロップ、スワイプなどのジェスチャー認識
- 物理演算ベースの自然なアニメーション
- 複雑なインタラクティブ UI の実装
- 最高レベルのアニメーション制御が必要な場合
総合的な推奨アプローチ
実際のプロジェクトでは、これら 3 つの手法を組み合わせて使用することが最も効果的です。
基本的な UI 遷移には CSS Transitions を使用し、バンドルサイズへの影響をゼロに抑えます。中規模のインタラクティブアニメーションには Motion One を採用し、軽量ながら高機能な実装を実現します。そして、高度なジェスチャーや物理演算が必要な部分にのみ Popmotion を導入するのです。
このようなハイブリッドアプローチにより、パフォーマンス、バンドルサイズ、機能性のバランスを最適化できます。
パフォーマンスとバンドルサイズの比較表
最後に、3 つの手法を数値で比較してみましょう。
| # | 手法 | バンドルサイズ | 60fps 達成率 | 学習時間 | 機能レベル |
|---|---|---|---|---|---|
| 1 | CSS Transitions | 0KB | 99% | 1 時間 | 基本 |
| 2 | Motion One | 約 5KB | 98% | 2-3 時間 | 中級 |
| 3 | Popmotion | 約 11KB | 95% | 5-8 時間 | 上級 |
これらの数値から、各手法のトレードオフが明確に理解できます。
次のステップ
本記事で紹介したコード例を実際に動かし、自分のプロジェクトに適用してみてください。それぞれのアニメーション手法の挙動を体感することで、より深い理解が得られるでしょう。
SolidJS のリアクティブシステムと組み合わせることで、パフォーマンスの高い魅力的な UI アニメーションを実現できます。ユーザー体験を向上させる素晴らしいアニメーションを作成してくださいね。
関連リンク
articleSolidJS のアニメーション比較:Motion One vs Popmotion vs CSS Transitions
articleSolidJS で無限ループが止まらない!createEffect/onCleanup の正しい書き方
articleSolidJS の Control Flow コンポーネント大全:Show/For/Switch/ErrorBoundary を使い分け
articleSolidJS 本番運用チェックリスト:CSP・SRI・Preload・エラーレポートの総点検
articleSolidJS クリーンアーキテクチャ実践:UI・状態・副作用を厳密に分離する
articleSolidJS フック相当 API 速見表:createSignal/createMemo/createEffect… 一覧
articleSolidJS のアニメーション比較:Motion One vs Popmotion vs CSS Transitions
articleClaude Code セットアップ最短ルート:macOS での導入から初回実行まで
articleShell Script でファイル操作を極める:find・rsync・圧縮/展開の実践レシピ
articleRuby で業務自動化:スプレッドシート連携・メール配信・定期バッチの実例
articleBun で Hello API:超軽量 HTTP サーバを 5 分で公開する
articleRedis Pub/Sub vs Redis Streams:配信保証とスケーラビリティ比較
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来