このノートではCSSとGSAPの基本的な実装を理解している前提で代表的な種類の差とJavaScriptでの利用を整理します。
DEMO
JavaScriptでの実装
スクロール量や経過時間などを0から1のprogressとして扱いイージング関数へ渡す方法です。
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をイージングして値を作ります。
以下の例ではprogressが0.4のときのvalueを求めます。
const progress = 0.4;
const value = easing( 'power1', 'inOut', progress );
console.log( value ); progressが0ならvalueは0、1なら1になります。Backなどオーバーシュートする種類ではこの範囲を超える場合があるのでvalueを0から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 ); この場合はprogressが0ならvalueは0、1なら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() のサンプリングで再現 */
}
power1とpower2のIn、Outは三次ベジェへ同じ曲線として置き換えられます。In Outは途中で数式が切り替わるため一つのcubic-bezier()では近似になります。power3とpower4も次数が三次を越えるので近似です。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を使うぐらいが管理しやすいと思います。
参考
- Easing Comparison – Garden Eight
- Easing – GSAP
- GSAP Core source
- CSS Easing Functions Module Level 2 – W3C
- ※ GSAPとCSSに関する記載は2026年7月22日時点の公式ドキュメントとGSAP 3.15.0を基準にしています。