HTML・CSS・Javascriptで作る「モーフィングアニメーション」

HTML・CSS・Javascriptで作る「モーフィングアニメーション」

「モーフィングアニメーション」は、「ある形」から「ある形」へシームレスに変化するアニメーションのことですが、「HTML」と「CSS」で作成する方法をご紹介したいと思います。

目次

「モーフィングアニメーション」の仕組み

「モーフィングアニメーション」は「パス」と呼ばれる情報を定義し、その「パスの位置」を移動させることで実現します。

「illustrator」をお使いの方は「illustrator」の「パス」や「クリッピングマスク」とよく似た機能になります。

CSSの「clip-path」プロパティ

「WEBサイト製作」では、「CSS」の「clip-path」プロパティを使うことで、「要素の表示範囲」を指定することができます。

「clip-pathの指定方法」にはさまざまなものがあります。

circle

「円」の形で表示領域を限定することができます。

例えば

のような長方形の画像に、

clip-path: circle(30%);

を適用すると、

のように表示されます。

「円の位置」を指定することもできます。

clip-path: circle(30% at 0px 0px);

と指定すると、

のように表示されます。

「円の中心」が「画像の左上」に配置され、ここが原点となります。

clip-path: circle(30% at 20px 50px);

と設定すると、

「at」の右横の「20px」の値を増やすと右に移動し、「50px」の値を増やすと下に移動します。

ellipse

「ellipse」は「楕円」で表示範囲を指定することができます。

のような画像に

clip-path: ellipse(80px 50px);

と指定すると、

のように表示されます。

「ellipse」で指定をしている「120px」は横方向の大きさで「80px」は縦方向の大きさになります。

「楕円」の位置を指定することもでき、「円」と同様に「画像の左上」が原点となります。

clip-path: ellipse(120px 80px at 20px 30px);

と指定をすると、「楕円の表示範囲」が「画像の左上」から「右方向へ20px」移動し、「下方向へ30px」移動します。

path

「SVG」のパス指定を用いて表示範囲を指定することができます。

例えば、

のような画像に、

clip-path: path("M0,0 L100,200 L50,300 Z");

を指定すると、

のように表示されます。

今回の「モーフィングアニメーション」では利用しない方法のため、詳しい指定方法は「SVGパスの定義方法」について調べてみてください。

polygon

「多角形」を指定して、表示範囲を指定することができます。

例えば、

のような画像に、

clip-path:polygon(0% 0%, 100% 10%, 91% 100%, 1% 82%);

を指定すると、

のように表示されます。

「モーフィングアニメーション」ではこの方法を利用していくため、詳しく見ていきたいと思います。

先ほどの設定は下図のようになっています。

画像の左上が「0%」で横方向の右端が「100%」。

そして、縦方向の下端が「100%」となっています。

clip-path:polygon(横方向1 縦方向1,  横方向2 縦方向2, ・・・);

のように表示範囲を囲むポイントを指定していきます。

「モーフィングアニメーション」の作り方

「モーフィングアニメーション」を作成するためには「2つのpolygon」が必要になります。

「polygon」の作り方

「変形前のpolygon」と「変更後のpolygon」を作成する必要がありますが、大切なことは「polygonのデータ数」を合わせることです。

例えば、「変形前のpolygon」の「データ数」が「4」であれば、「変更後のpolygon」も「データ数」を「4」にする必要があります。

今回は下のような写真を利用して「モーフィングアニメーション」を作っていきたいと思います。

ワッフルの部分を表示範囲に設定してみたいと思います。

では、どのように「polygon」の設定値を求めるのかですが、あらかじめ、「0%~100%」の「横と縦の格子状のシート」を用意しておく方法があります。

この「格子状のシート画像」を「表示したい画像」と重ね合わせます。

表示を限定したい範囲の「ポイントの値」を取得します。

ワッフルを表示範囲にしたいため「ワッフル」の4隅のポイントを調べます。

clip-path:polygon(38% 38%, 59% 53%, 45% 82%, 25% 66%);

この値を適用してみると、

のように表示されます。

この状態を「アニメーション前の状態」とします。

次に「アニメーション後の状態」を定義したいと思いますが、「アニメーション後」は「画像全体」を表示したいので、「画像の4隅のポイント」を取得します。

このポイントの「clip-path」は、

clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);

のようになります。

「アニメーション」の作成

「ワッフル」の画像にマウスが重なった時にアニメーションをしたいと思います。

パソコンをお使いの方は、下のワッフル画像にマウスカーソルを合わせてみてください。

「ワッフルの背景画像」が表示されると思います。

この画像の「HTMLコード(img要素)」は、

<img src="https://www.webdesign-ls.com/wp-content/uploads/2023/11/morph_anim_002.jpg" class="morph_img_001">

のようになっています。

CSSは、

.morph_img_001 {
    /* マウスカーソルを重ねる前 */
    clip-path: polygon(38% 38%, 59% 53%, 45% 82%, 25% 66%);
    transition: all 1s ease;
}

.morph_img_001:hover {
    /* マウスカーソルを重ねた後 */
    clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
}

のようになります。

「マウスオーバー(ホバー)」では無く、「クリック」など他のタイミングでアニメーションしたい場合は「Javascript」などを利用すると実現することができます。

今回は4点でしたが「polygon」の「頂点(ポイント)」数は増やすことができます。

「clip-path」の値を「アニメーション前後」で入れ替えると、「マウスオーバー」することで、画像の表示範囲を限定することもできます。

例えば、

.morph_img_002 {
    /* マウスカーソルを重ねる前 */
    clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
    transition: all 1s ease;
}

.morph_img_002:hover {
    /* マウスカーソルを重ねた後 */
    clip-path: polygon(38% 38%, 59% 53%, 45% 82%, 25% 66%);
}

のように作成すると、

「マウスカーソル」を画像に重ねることで、表示範囲がが限定されます。

「polygon」が多数の「モーフィングアニメーション」

「人物」のような複雑な写真なども同様に表示することができます。

例えば、

のような写真の人物の表示範囲を限定するためには、

clip-path:polygon(44% 38%, 45% 36%, 47% 34%, 49% 33%, 52% 33%, 55% 35%, 58% 39%, 59% 41%, 59% 43%, 61% 45%, 64% 45%, 66% 48%, 67% 51%, 67% 55%, 66% 59%, 65% 62%, 65% 65%, 66% 75%, 68% 86%, 68% 87%, 67% 88%, 58% 93%, 61% 100%, 52% 100%, 49% 96%, 48% 92%, 46% 89%, 45% 92%, 44% 96%, 44% 100%, 36% 100%, 35% 95%, 35% 91%, 35% 85%, 35% 79%, 36% 74%, 38% 70%, 38% 68%, 38% 62%, 39% 57%, 41% 54%, 43% 51%, 42% 48%, 41% 46%, 41% 43%, 42% 40%);

のような多数のポイント指定が必要になります。

このポイントを元に写真を表示すると、

のようになります。

「モーフィングアニメーション」を作りましたので、PCの方は下の写真にマウスを重ねてみてください。

「複雑な形」でも「モーフィングアニメーション」ができますが、「アニメーション前後」の「ポイント数」を合わせないとうまくアニメーションしてくれません。

「Javascript」を利用した「モーフィングアニメーション」

「Javascript」を利用すると「任意のタイミング」でアニメーションを行うことができます。

2STEPのモーフィングアニメーション

例えば、ある要素が「画面内に表示された時」や「クリックされた時」など、さまざまなタイミングで「アニメーションの表示」を行うことが可能です。

このまま下にスクロールしてみてください。

画像が画面に表示されるタイミングでアニメーションが実行されます。

アニメーションが実行されない場合は再読み込みをしてみてください。

これまでは、「transition」を利用したシンプルなアニメーションでしたが、今回は「animationプロパティ」を利用した「2STEPのアニメーション」となっています。

HTMLは、

<img src="https://www.webdesign-ls.com/wp-content/uploads/2023/11/006.jpg"  class="morph_img_004">

のように「画像の要素」を作成し、CSSは、

.morph_img_004 {
    clip-path: polygon(49% 49%, 50% 49%, 50% 50%, 49% 50%);
    opacity: 0;
}
.morph_img_004.active {
    animation: clip-path-anim 1s ease-in-out 0s forwards;
}

@keyframes clip-path-anim {
    0% {
        opacity: 1;
        clip-path: polygon(49% 49%, 50% 49%, 50% 50%, 49% 50%);
    }

    /* 横方向いっぱいまで広がる */
    30% {
        clip-path: polygon(0% 49%, 100% 49%, 100% 50%, 0% 50%);
    }

    /* 画像の大きさいっぱいまで広がる */
    100% {
        opacity: 1;
        clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0 100%);
    }
}

のようになっています。

アニメーションの「@keyframes」を見ると、「0%~30%」までは横方向いっぱいに広がるアニメーションで、「30%~100%」までは画像の大きさいっぱいまで広がるアニメーションになっています。

「Javascript(jQuery)」は、

$(document).ready(function(){
    $(window).scroll(function(){
        /* 「画面の下端」が「画像の位置」より下になった時 */
        if($('.morph_img_004').offset().top < $(window).scrollTop() + $(window).height()){
            if( !$('.morph_img_004').hasClass('active') ){
                /* 画像に「activeクラス」を追加してアニメーションをスタート */
                $('.morph_img_004').addClass('active');
            }
        }
    });
});

のようになっています。

画像が画面内に来たタイミングで画像に「active」というクラスを追加してアニメーションを実行しています。

アイディアしだいでさまざまな「アニメーションパターン」を作ることができます。

さらにスクロールしてみてください。

このアニメーションのHTMLは、

<img src="https://www.webdesign-ls.com/wp-content/uploads/2023/11/006.jpg"  class="morph_img_005">

のように作成し、

.morph_img_005 {
    clip-path: polygon(49% 49%, 50% 49%, 50% 50%, 49% 50%);
    opacity: 0;
}
.morph_img_005.active {
    animation: clip-path-anim02 1s ease-in-out 0s forwards;
}

@keyframes clip-path-anim02 {
    0% {
        opacity: 1;
        clip-path: polygon(49% 49%, 50% 49%, 50% 50%, 49% 50%);
    }

    30% {
        clip-path: polygon(0% 0%, 50% 49%, 100% 100%, 49% 50%);
    }

    100% {
        opacity: 1;
        clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0 100%);
    }
}

のようになっています。

複数STEPのモーフィングアニメーション

2STEPだとシンプルなモーフィングアニメーションしか作れませんが、複数STEPのモーフィングアニメーションは多彩な表現を行うことができます。

このままスクロールしてみてください。

Javascriptはこれまでと変わりませんが、CSSの設定量が増えています。

.morph_img_006 {
            width: 1000px;
            height: 667px;
            clip-path: polygon(46% 32%, 48% 30%, 51% 28%, 53% 28%, 55% 28%, 58% 29%, 60% 31%, 61% 34%, 62% 37%, 63% 40%, 63% 43%, 62% 49%, 60% 53%, 58% 55%, 57% 56%, 53% 57%, 49% 56%, 46% 54%, 44% 50%, 43% 47%, 42% 42%, 43% 37%, 44% 34%);
            opacity: 1;
        }

        .morph_img_006.active {
            animation: clip-path-anim03 5s ease-in-out 0s forwards;
        }

        @keyframes clip-path-anim03 {
            0% {
                opacity: 1;
                clip-path: polygon(46% 32%, 48% 30%, 51% 28%, 53% 28%, 55% 28%, 58% 29%, 60% 31%, 62% 34%, 63% 37%, 64% 40%, 64% 43%, 63% 49%, 61% 53%, 59% 55%, 57% 57%, 53% 58%, 49% 56%, 46% 54%, 44% 50%, 43% 47%, 42% 42%, 43% 37%, 44% 34%);
            }

            10% {
                clip-path: polygon(59% 65.5%, 61% 67.5%, 63% 68.5%, 65% 70%, 68% 73%, 70% 75%, 72% 76%, 70% 82%, 68.5% 86%, 67% 90%, 66% 94%, 65% 97%, 62% 95%, 59% 92%, 57% 90%, 54% 88%, 51% 86%, 52% 84%, 54% 80%, 55% 76%, 56% 73%, 57% 70%, 58% 67%);
            }

            20% {
                clip-path: polygon(59% 65.5%, 61% 67.5%, 63% 68.5%, 65% 70%, 68% 73%, 70% 75%, 72% 76%, 70% 82%, 68.5% 86%, 67% 90%, 66% 94%, 65% 97%, 62% 95%, 59% 92%, 57% 90%, 54% 88%, 51% 86%, 52% 84%, 54% 80%, 55% 76%, 56% 73%, 57% 70%, 58% 67%);
            }

            30% {
                clip-path: polygon(26.5% 72%, 27.5% 69%, 29% 67%, 31% 65%, 34.5% 63%, 38% 63%, 41% 64%, 43% 66%, 45% 69%, 46.5% 72%, 47% 76%, 47% 79%, 46.2% 85%, 45% 89%, 43% 92%, 40% 94%, 36% 96%, 33% 96%, 30% 94%, 27.2% 90%, 26% 86%, 25% 82%, 25% 79%);
            }

            40% {
                clip-path: polygon(26.5% 72%, 27.5% 69%, 29% 67%, 31% 65%, 34.5% 63%, 38% 63%, 41% 64%, 43% 66%, 45% 69%, 46.5% 72%, 47% 76%, 47% 79%, 46.2% 85%, 45% 89%, 43% 92%, 40% 94%, 36% 96%, 33% 96%, 30% 94%, 27.2% 90%, 26% 86%, 25% 82%, 25% 79%);
            }

            50% {
                clip-path: polygon(75% 40%, 78% 38%, 81% 38%, 83% 38%, 86% 40%, 89% 44%, 91% 48%, 91.5% 53%, 91.5% 57%, 90% 61%, 88.5% 64.5%, 87% 65.8%, 85% 67.2%, 82% 68.2%, 79% 68%, 76% 66%, 74% 64%, 73% 62%, 72% 59%, 71% 56%, 71% 53%, 71% 49%, 72% 45%);
            }

            60% {
                clip-path: polygon(75% 40%, 78% 38%, 81% 38%, 83% 38%, 86% 40%, 89% 44%, 91% 48%, 91.5% 53%, 91.5% 57%, 90% 61%, 88.5% 64.5%, 87% 65.8%, 85% 67.2%, 82% 68.2%, 79% 68%, 76% 66%, 74% 64%, 73% 62%, 72% 59%, 71% 56%, 71% 53%, 71% 49%, 72% 45%);
            }

            70% {
                clip-path: polygon(21% 31%, 23% 29%, 26% 27%, 29% 26%, 31% 27%, 34% 29%, 36% 31%, 37% 33%, 38% 36%, 38% 42%, 37% 47%, 35% 50%, 32% 53%, 29% 55%, 26% 55%, 23% 54%, 21% 53%, 20% 51%, 19% 48%, 18% 45%, 18% 41%, 19% 36%, 20% 33%);
            }

            80% {
                opacity: 1;
                clip-path: polygon(21% 31%, 23% 29%, 26% 27%, 29% 26%, 31% 27%, 34% 29%, 36% 31%, 37% 33%, 38% 36%, 38% 42%, 37% 47%, 35% 50%, 32% 53%, 29% 55%, 26% 55%, 23% 54%, 21% 53%, 20% 51%, 19% 48%, 18% 45%, 18% 41%, 19% 36%, 20% 33%);
            }

            90% {
                opacity: 0;
                clip-path: polygon(47% 47%, 47% 46%, 47% 45%, 47% 44%, 47% 43%, 47% 42%, 47% 41%, 47% 40%, 47% 39%, 47% 38%, 48% 38%, 49% 38%, 50% 38%, 51% 38%, 52% 38%, 53% 38%, 54% 38%, 55% 38%, 56% 38%, 57% 38%, 53% 41%, 52% 43%, 50% 45%);
            }

            100% {
                opacity: 1;
                clip-path: polygon(1% 1%, 18% 1%, 39% 1%, 66% 1%, 85% 1%, 100% 1%, 100% 15%, 100% 37%, 100% 59%, 100% 79%, 100% 100%, 89% 100%, 74% 100%, 57% 100%, 46% 100%, 33% 100%, 18% 100%, 1% 100%, 1% 86%, 1% 71%, 1% 53%, 1% 39%, 1% 20%);
            }
        }

作成する「clip-path」のデータ量も増えるため作成に時間がかかりますが、「モーフィングアニメーション」は見た目のインパクトもあるため、「注目してほしいポイント」に効果的に使うと良いのではないでしょうか。

ぜひご自身の「オリジナルモーフィングアニメーション」の作成にチャレンジしてみていただければと思います。

この記事を書いた人

システム開発会社のWEBデザイン部で「デザイン&サイト構築」を担当しています。

目次