Skip to main content
GDN8 PATIO

イージング関数の実装と進捗への適用

このノートではCSSとGSAPの基本的な実装を理解している前提で代表的な種類の差とJavaScriptでの利用を整理します。

JavaScriptでの実装

スクロール量や経過時間などを0から1progressとして扱いイージング関数へ渡す方法です。

GSAPを導入できない場面やイージングの計算だけを使う場合の実装です。常に容量にはシビアなので思った以上に活躍します。

種類は普段の制作からイメージしやすいようにGSAPのイージングへ合わせています。power1からpower4はGSAP独自の名称です。ただ曲線自体は一般的な多項式イージングで、power1はQuad(二次)、power2はCubic(三次)、power3はQuart(四次)、power4はQuint(五次)に対応します。GSAPでは次数が上がるほど変化が強くなる関係をPowerという同じ名前で並べています。

const EasingIn = {
	linear: t => t,
	power1: t => t ** 2,
	power2: t => t ** 3,
	power3: t => t ** 4,
	power4: t => t ** 5,
	sine: t => 1 - Math.cos( t * Math.PI / 2 ),
	expo: t => t === 0 ? 0 : 2 ** ( 10 * t - 10 ),
	circ: t => 1 - Math.sqrt( 1 - t ** 2 ),
	back( t ) {
		const overshoot = 1.70158;

		return ( overshoot + 1 ) * t ** 3 - overshoot * t ** 2;
	}
};

function easing( type, direction, t ) {
	switch ( direction ) {
		case 'in':
			return EasingIn[ type ]( t );
		case 'out':
			return 1 - EasingIn[ type ]( 1 - t );
		case 'inOut':
			return t < 0.5
				? EasingIn[ type ]( t * 2 ) / 2
				: 1 - EasingIn[ type ]( ( 1 - t ) * 2 ) / 2;
		default:
			throw new Error( `Unknown easing direction: ${ direction }` );
	}
}

easing()の第1引数で種類、第2引数で方向、第3引数で進捗を指定します。Outは入力と出力を反転します。In Outは前半へIn、後半へ反転したInを適用します。Expoの条件分岐は開始値を正確な0にするためです。これはGSAPの内部実装を再現するものではありません。GSAPが使える環境で曲線を完全に一致させる場合はgsap.parseEase( 'expo.out' )などを利用します。

進捗から値を作る

スクロール量やドラッグ量などから得たprogressをイージングして値を作ります。
以下の例ではprogress0.4のときのvalueを求めます。

const progress = 0.4;
const value = easing( 'power1', 'inOut', progress );
console.log( value );

progress0ならvalue01なら1になります。Backなどオーバーシュートする種類ではこの範囲を超える場合があるのでvalue0から100など別の範囲へ変換するときはlerp()を使います。

function lerp( start, end, progress ) {
	return start + ( end - start ) * progress;
}
const progress = 0.4;
const value = lerp( 0, 100, easing( 'power1', 'inOut', progress ) );
console.log( value );

この場合はprogress0ならvalue01なら100になります。

動きは進捗によるイージングのデモで確認できます。

経過時間から進捗を作る

次は1200msかけて0から1まで変化するPower1 In Outの値をコンソールへ出す例です。

const startedAt = performance.now();
function update( now ) {
	const progress = Math.min( ( now - startedAt ) / 1200, 1 );
	console.log( easing( 'power1', 'inOut', progress ) );
	if ( progress < 1 ) requestAnimationFrame( update );
}

update( startedAt );

progressは経過時間を1200msで割った値です。Power1 In Outを通すことで増加量は開始と終了付近で小さく、中間付近で大きくなります。

CSSでのイージング

CSSのcubic-bezierをつかって近似のイージングを登録することでJSのアニメーションとの整合性をとることができます。JSを使用しないシーンでも使用できるので便利です。曲線と実際の動きはイージングの比較デモで確認できます。

:root {
	--ease-none: linear;
	--ease-power1-in: cubic-bezier(0.333333, 0, 0.666667, 0.333333);
	--ease-power1-out: cubic-bezier(0.333333, 0.666667, 0.666667, 1);
	--ease-power1-in-out: cubic-bezier(0.455, 0.03, 0.515, 0.955);
	--ease-power2-in: cubic-bezier(0.333333, 0, 0.666667, 0);
	--ease-power2-out: cubic-bezier(0.333333, 1, 0.666667, 1);
	--ease-power2-in-out: cubic-bezier(0.645, 0.045, 0.355, 1);
	--ease-power3-in: cubic-bezier(0.5, 0, 0.75, 0);
	--ease-power3-out: cubic-bezier(0.25, 1, 0.5, 1);
	--ease-power3-in-out: cubic-bezier(0.76, 0, 0.24, 1);
	--ease-power4-in: cubic-bezier(0.64, 0, 0.78, 0);
	--ease-power4-out: cubic-bezier(0.22, 1, 0.36, 1);
	--ease-power4-in-out: cubic-bezier(0.83, 0, 0.17, 1);
	--ease-sine-in: cubic-bezier(0.12, 0, 0.39, 0);
	--ease-sine-out: cubic-bezier(0.61, 1, 0.88, 1);
	--ease-sine-in-out: cubic-bezier(0.37, 0, 0.63, 1);
	--ease-expo-in: cubic-bezier(0.7, 0, 0.84, 0);
	--ease-expo-out: cubic-bezier(0.16, 1, 0.3, 1);
	--ease-expo-in-out: cubic-bezier(0.87, 0, 0.13, 1);
	--ease-circ-in: cubic-bezier(0.55, 0, 1, 0.45);
	--ease-circ-out: cubic-bezier(0, 0.55, 0.45, 1);
	--ease-circ-in-out: cubic-bezier(0.85, 0, 0.15, 1);
	--ease-back-in: cubic-bezier(0.36, 0, 0.66, -0.56);
	--ease-back-out: cubic-bezier(0.34, 1.56, 0.64, 1);
	--ease-back-in-out: cubic-bezier(0.68, -0.6, 0.32, 1.6);
	--ease-steps: steps(9, jump-none);
	/* bounce / elastic は linear() のサンプリングで再現 */
}

power1power2InOutは三次ベジェへ同じ曲線として置き換えられます。In Outは途中で数式が切り替わるため一つのcubic-bezier()では近似になります。power3power4も次数が三次を越えるので近似です。BounceやElasticはgsap.parseEase()で得た関数を等間隔に評価するとCSSへ変換できます。

function easeToLinear( name, points = 80 ) {
	const ease = gsap.parseEase( name );
	const values = [];

	for ( let index = 0; index <= points; index++ ) {
		values.push( Number( ease( index / points ).toFixed( 4 ) ) );
	}

	return `linear(${ values.join( ', ' ) })`;
}

点が多いほど元の曲線へ近づきます。ただCSSが長くなるので対象ブラウザ、曲線の細かさ、再生時間を見ながら決めます。

上記以外のEasing

標準の種類で足りない場合は次のEaseもあります。

種類 パッケージ 用途
RoughEase EasePack 不規則な揺れやノイズ
SlowMo EasePack 中間区間だけをゆっくり見せる
ExpoScaleEase EasePack 拡大縮小を視覚上の一定速度へ近づける
CustomEase Plugin SVG Pathや制御点から任意の曲線をつくる
CustomBounce Plugin 跳ねる強さやSquashを調整する
CustomWiggle Plugin 振動回数や揺れ方を調整する

まずCoreの種類で方向と強さを決め、それで表せない動きに限って追加のEaseを使うぐらいが管理しやすいと思います。

参考

  • ※ GSAPとCSSに関する記載は2026年7月22日時点の公式ドキュメントとGSAP 3.15.0を基準にしています。