2020
01/30

Elastic/Bounce系イージングをSassのfunctionで実装する

CSSアニメーションのイージングはcubic-bezierを指定すれば簡単にできますが、ElasticやBounceのような行ったり来たりするイージングはcubic-bezierだけでは指定することはできません。

イージングについてはEasing Functions Cheat Sheetが分かりやすいです。
Easing Functions Cheat Sheet

ほとんどはcubic-bezierで事足りるのですが、より凝ったアニメーションのためにElasticやBounceを使いたいと思い、Sassで簡単に作れるfunctionを書いてみました。

デモ
Github

ADs

jQuery Easingの計算式を参考に

イージングを計算式で指定することができればなんとかなりそうです。
そこでjQuery Easing Pluginは計算でイージングを定義していたことを思い出し、プラグイン内で使っている関数をパク…参考にしました。

jQuery Easing Plugin

三角関数の計算ができるMathSassの導入

jQuery.easingの関数は一部三角関数を使っているので、Sassで三角関数や各種計算ができるMathSassという関数ライブラリをダウンロードします。

MathSass
Github

mathsassフォルダ内の「_math.scss」をインポートすれば、JavascriptのMath関数のようにsinやcosが使えるようになります。

JavascriptのMathに相当する関数はDart Sassならネイティブにサポートされています。私はLibSassなので…。
sass:math

functionを書く

jQuery.easingのElastic,BounceイージングをSassで使えるように書き直します。
timing-functionが使えるので使うことはないと思いますが、easeOutQuitやeaseInExpoなども関数化することができます。

easeInElastic

easeOutElastic

easeInOutElastic

easeOutBounce

easeInBounce

easeInOutBounce

使い方

これで各イージングを定義するfunctionができました。
次にこれらのイージングをanimationに適用します。

animationプロパティの指定は通常のCSSと同じです。

次に「easing1」に適用するためのkeyframesを書きます。

長くなりましたが、変更箇所は

$wtart,$end,$startp,$endp,$stepの各変数
アニメーションさせるプロパティ
(ここではtransform)

の2点です。
$stepを細かくするとなめらかになりますが、その分keyframesを細かく出力するためCSSが長くなります。
プロパティ部分は

easeInElastic
easeOutElastic
easeInOutElastic
easeInBounce
easeOutBounce
easeInOutBounce

から選びます。

コピペで済むもののもうちょっとシンプルにしたい……。
Sassにヒアドキュメントかechoするだけの機能があればなんとかなったのですが。

まとめ

これらのイージングは近似値をkeyframesに当てはめていますので、$stepと移動距離の兼ね合いによってはなめらかにならない場合があります。
しかし手作業でkeyframesを書くより少しは楽に…なっているでしょうか(;´∀`)

…ここまでやるならanime.jsでいいかな、とも思います。

ADs

Post Comments

メールアドレスが公開されることはありません。

Comments

こんにちは。まったく同じことをしようとしていて検索して見つけまして、とても参考になりました。
@keyframes内はそのままmixinにしてあげれば、実装はシンプルに済みますよ。具体的には以下のような感じで…

// 追加function、mixin内でeasingを出し分けるための関数
@function customEasingValue($eas, $t, $s, $c, $d, $u: px){
    $return: ”;
    @if $eas == ie {
        $return: easeInElastic($t, $s, $c, $d);
    } @elseif $eas == oe {
        $return: easeOutElastic($t, $s, $c, $d);
    } @elseif $eas == ioe {
        $return: easeInOutElastic($t, $s, $c, $d);
    } @elseif $eas == ib {
        $return: easeInBounce($t, $s, $c, $d);
    } @elseif $eas == ob {
        $return: easeOutBounce($t, $s, $c, $d);
    } @elseif $eas == iob {
        $return: easeInOutBounce($t, $s, $c, $d);
    }
    @return round($return * 100) / 100 * 1#{$u};
}

/**
* 追加mixin、@keyframesの中で呼び出す
* $eas     : easing関数の指定
* $prop : アニメーションさせるプロパティ
* $prop2: transform時専用、関数値の指定
* $s     : 開始値
* $e     : 終了値
* $sp     : 開始%
* $ep     : 終了%
* $step : 分割数
* $u     : 値の単位(px、em、%など)
*/
@mixin customEasingKeyframes($eas, $prop, $prop2: ”, $s: 0, $e: 400, $sp: 0, $ep: 100, $step: 20, $u: px){
    $i: 0;
    $c: $e – $s;
    @while $i <=$step {
        $t: (($ep – $sp) / $step / 100) * $i;
        $d: ($ep – $sp) / 100;
        $percent: $sp + (($ep – $sp) / $step) * $i;

        #{$percent * 1%} {
            $val: customEasingValue($eas, $t, $s, $c, $d, $u);
            $property: $prop;
            @if $property == transform {
                $val: #{$prop2}#{"("}#{$val}#{")"};
            }
            #{$property}: #{$val};
        }

        $i: $i+1;
    }
}

こうすれば、@keyframesは以下のような感じで1行で済みます。

@keyframes uekara_ochiru {
    @include customEasingKeyframes(ob, margin-top, $s: -60, $e: 0, $u: px);
}
@keyframes araburu_kaiten {
    @include customEasingKeyframes(ioe, transform, rotate, -240, 0, $u: deg);
}

2つ以上のプロパティを組み合わせたい場合はcustomEasingKeyframesを増やせばOKです。ただし出力結果がすごい長くなるのが難点ですが…

@keyframes ochi_nagara_araburu {
    @include customEasingKeyframes(ob, margin-top, $s: -60, $e: 0, $u: px);
    @include customEasingKeyframes(ioe, transform, rotate, -240, 0, $u: deg);
}

transformを複数組み合わせる場合はceky()の$prop2以降を配列にして渡して、$prop2の数だけeachして計算してcustomEasingValue()の結果を半角スペースでつないで…、みたいな感じにすればたぶんいけますが、面倒なのと僕の用途では必要なかったのでやっていません…

  • 匿名希望
  • 2022年3月24日 9:56 PM