ease-in や cubic-bezier() などの従来の CSS イージング関数は単純な曲線に限定されているため、バウンスやスプリングなどの複雑な物理ベースの効果を作成することはできません。linear() タイミング関数は、複雑な曲線を近似できる一連のストップを指定できるようにすることで、この問題を解決します。トランジションとアニメーションは、ストップ間の直線に基づいて補間されますが、十分なストップがあれば、滑らかに表示されます。
実装の手順
- カーブストップを生成する:
バネやバウンスのために数十個のポイントを手動でプロットするのは現実的ではありません。外部ライブラリのタイミング関数を使用するか、ツールを使用して既存の JavaScript イージング関数または SVG パスを
linear()構文に変換します。省略可: これらのタイミング関数を CSS カスタム プロパティとして保存し、サイト全体で再利用します。 - タイミング関数を定義する: 生成されたストップを
transition-timing-functionプロパティまたはanimation-timing-functionプロパティに適用するか、transitionまたはanimationのショートハンドを使用して適用します。 - 期間を調整する: 期間が物理プロパティ(質量、剛性)から派生する JavaScript 物理エンジンとは異なり、CSS では固定の
durationが必要です。意図した効果を得るには、期間の調整が必要になる場合があります。
例: スプリング イージング
この例では、カスタム linear() 関数を使用して、ターゲット値をオーバーシュートしてから落ち着くスプリング効果を作成する方法を示します。
.spring {
/* Define the physics-based easing as a reusable variable */
--spring-easing: linear(0, 0.016 0.5%, 0.06 1%, 0.226 2%, 1.116 5.4%, 1.375 6.6%, 1.527 7.7%, 1.565 8.2%, 1.585 8.8%, 1.581 9.3%, 1.559 9.8%, 1.458 10.9%, 0.937 14.3%, 0.784 15.5%, 0.693 16.6%, 0.67 17.1%, 0.657 17.7%, 0.671 18.7%, 0.729 19.8%, 1.042 23.3%, 1.13 24.5%, 1.182 25.6%, 1.201 26.7%, 1.192 27.7%, 1.156 28.8%, 0.977 32.2%, 0.925 33.4%, 0.894 34.5%, 0.882 35.6%, 0.887 36.6%, 0.907 37.7%, 1.045 42.4%, 1.069 44.5%, 1.059 46.3%, 0.979 50.9%, 0.96 53.4%, 0.966 55.3%, 1.013 59.9%, 1.024 62.3%, 0.986 71.2%, 1.008 79.9%, 0.995 88.9%, 1);
/* Apply the easing with a duration that fits the spring's complexity */
/* MANDATORY: Always include a duration; linear() does not calculate it automatically */
transition: scale 0.8s var(--spring-easing);
}
.spring:hover {
scale: 1.2;
}
例: バウンス イージング
この例では、カスタム linear() 関数を使用してバウンス効果を作成する方法を示します。
.bounce {
/* Define the physics-based easing as a reusable variable */
--bounce-easing: linear(0, 0.214 14.7%, 0.386 23.7%, 0.598 31.9%, 0.999 44.7%, 0.807 52.6%, 0.762 56%, 0.747 59.4%, 0.758 62.4%, 0.793 65.6%, 0.999 77.4%, 0.961 81.2%, 0.949 84.8%, 0.956 88%, 0.993 95.5%, 1);
/* Apply the easing with a duration that fits the bounce's complexity */
/* MANDATORY: Always include a duration; linear() does not calculate it automatically */
transition: scale 0.4s var(--bounce-easing);
}
.bounce:hover {
scale: 1.2;
}
考慮すべきポイント
- パフォーマンス: 物理ベースのアニメーションを最もスムーズにするには、
transformやopacityなど、別のスレッドで実行されるプロパティにlinear()を適用します。 - 精度とペイロード: ストップを増やすと曲線が滑らかになりますが、CSS のサイズも大きくなります。ほとんどのジェネレーターでは、曲線を「簡素化」して、滑らかさとコードサイズの最適なバランスを見つけることができます。
- バウンスに不透明度を使用しない:
opacityにバウンス イージングを適用すると、値が 0 を下回ったり 1 を上回ったりした場合に、視覚的に不快なちらつきが発生することがあります。 - ユーザー補助: 物理ベースの複雑なアニメーションは、一部のユーザーにとって気が散ったり、モーション センシティビティを引き起こしたりする可能性があります。これらのアニメーションを減らすか無効にすることで、常にユーザー設定を尊重します。
@media (prefers-reduced-motion: reduce) {
.element {
transition: none;
}
}
代替戦略
CSS の代替
linear() をサポートしていないブラウザ向けに、フォールバックとして標準のイージング関数を用意します。ブラウザは、linear() 値を認識できない場合は無視し、以前の有効な宣言にフォールバックします。
.element {
/* Fallback for older browsers (standard smooth exit) */
transition: transform 0.8s ease-out;
/* Modern browsers will override with the physics-based easing */
transition-timing-function: linear(0, 1.1, 0.95, 1.02, 1);
}
JavaScript ライブラリのフォールバック(Motion / GSAP)
省略可: 古いブラウザでも高忠実度の物理アニメーションが不可欠な場合は、Motion(motion.dev)や GSAP(greensock.com)などの JavaScript ライブラリを使用して、linear() がサポートされていない場合にアニメーションを処理します。
- サポートを検出する:
CSS.supports()を使用して、ブラウザがlinear()関数を処理するかどうかを確認します。 - 条件付きで読み込み / 適用する: サポートされていない場合は、ライブラリのバネまたはバウンスの実装を使用します。
/* Detect if the browser supports the linear() function */
const supportsLinearEasing = window.CSS && CSS.supports('animation-timing-function', 'linear(0, 1)');
if (!supportsLinearEasing) {
/*
Example using Motion (motion.dev) for a spring fallback.
This should only be initialized if native CSS support is missing.
*/
import("https://cdn.jsdelivr.net/npm/motion@latest/dist/motion.js").then(({ animate, spring }) => {
animate(".element", { transform: "scale(1.2)" }, {
easing: spring({ stiffness: 100, damping: 10 })
});
});
}
CSS で @supports を使用して、より明示的な機能検出を行うこともできます。
@supports not (animation-timing-function: linear(0, 1)) {
.element {
/* Alternative experience for unsupported browsers */
transition-duration: 0.4s;
transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
}
}