株式会社グローバルゲート公式ブログ

Blog

2019-12-24

anime.jsとjQueryとCSSを使ったボカロ動画みたいなアニメーション

こんにちは。株式会社グローバルゲートのモーリーです。

紅白の出場歌手が発表されましたが、今年は米津玄師さんは出ない可能性が高そうですね。2020年に嵐に楽曲を提供するそうなので、そちらを楽しみにして、紅白はLiSAさんとおしりたんていに注目したいと思います。

さて、米津玄師さんのキャリアはボカロPからはじまっているのはご存知だと思いますが、ボカロ楽曲の動画は静止画のイラストに歌詞を組み合わせたアニメーションとして作成されていることが多いです。

(最近はMMDやLive2Dを使ったハイクオリティなアニメーションも増えてきてます)

Web制作では音楽をつけることはめったにありませんが、静止画+テキストでアニメーションという表現技法は管理や更新が簡単でありながらもインパクトがあっていいのではと思い、作成してみました。



まずは完成品をご覧ください


今回はCSSとjQueryのほか、anime.jsというJavascriptライブラリを使用しました。

https://globalgatej.github.io/animationLikeVocaloid/




全ソースをGithubに公開していますので、ご興味のある方はご覧ください。


https://github.com/globalgatej/animationLikeVocaloid



会社用のGithubアカウントも開設してしまった…草まみれにするようにがんばります。



HTML


HTMLはできるだけシンプルに、背景画像を設定したdivとテキストだけにします。

    <div id="keyvisual">
     <div class="keyvisual_main">
         <div class="keyvisual_item" style="background-image: url(img1.jpg)">
             <p>いつからこんなに大きな</p>
         </div>
         <div class="keyvisual_item" style="background-image: url(img2.jpg)">
             <p>思い出せない記憶があったか</p>
         </div>
         <div class="keyvisual_item" style="background-image: url(img3.jpg)">
             <p>どうにも憶えてないのを</p>
         </div>
         <div class="keyvisual_item" style="background-image: url(img4.jpg)">
             <p>ひとつ確かに憶えてるんだな</p>
         </div>

         <div class="keyvisual_item" style="background-image: url(img1.jpg)">
             <p>もう一回何回やったって</p>
         </div>
         <div class="keyvisual_item" style="background-image: url(img2.jpg)">
             <p>思い出すのはその顔だ</p>
         </div>
         <div class="keyvisual_item" style="background-image: url(img3.jpg)">
             <p>それでもあなたがなんだか</p>
         </div>
         <div class="keyvisual_item" style="background-image: url(img4.jpg)">
             <p>思い出せないままでいるんだな</p>
         </div>
     </div>

     <div class="keyvisual_loading">
         <div class="loading_item"></div>
     </div>
 </div>

各div.keyvisual_itemが順繰りで表示され、その間にテキストが一文字ずつ表示される、という流れです。

前処理としてアニメーション定義やテキストへの編集をJavascriptで行うため、アニメーション開始まで時間がかかります。ローディングを忘れずに。


CSS

#globalheader {
 padding: 40px 20px;
}
#globalheader h1 {
 font-size: 1.2rem;
 font-weight: 700;
}
#keyvisual {
 position: relative;
 height: 600px;
 background: #000;
}
.keyvisual_item {
 position: absolute;
 left: 0;
 top: 0;
 width: 100%;
 height: 100%;
 background-position: center center;
 background-size: cover;
}
.keyvisual_item p {
 font-family: "Noto Serif JP", "BIZ UDPMincho","ヒラギノ明朝 ProN W6", "HiraMinProN-W6", "HG明朝E", serif;
 font-weight: 700;
 color: #fff;
 font-size: 3rem;
 position: absolute;
 width: 100%;
 left: 0;
 top: 50%;
 margin-top: -1rem;
 text-align: center;
}
main {
 padding: 20px;
}
main p:not(:last-child) {
 margin-bottom: 1rem;
}
#copy {
 text-align: center;

}

/* loading用 */
.keyvisual_loading {
 position: absolute;
 left: 0;
 top: 0;
 width: 100%;
 height: 100%;
 background: #222;
 display: flex;
 z-index: 100;
 align-items: center;
 justify-content: center;
}
.loading_item {
 flex: none;
 width: 30px;
 height: 30px;
 background: #fff;
 animation: loading 0.5s linear infinite;
}
@keyframes loading {
 0% {
     transform: rotate(0);
 }
 100% {
     transform: rotate(360deg);
 }
}
body.loaded .loading_item {
 animation: loading_end 1s linear;
}
@keyframes loading_end {
 0% {
     transform: rotate(0);
 }
 100% {
     transform: rotate(360deg);
 }
}
body.loading_end .loading_item {
 animation: loading_finish 0.4s linear forwards;
}
@keyframes loading_finish {
 0% {
     opacity: 1;
     height: 30px;
     width: 30px;
 }
 50% {
     opacity: 1;
     height: 30px;
     width: 100%;
 }
 100% {
     opacity: 0;
     width: 100%;
     height: 100%;
 }
}

/* アニメーション用の初期設定 */

.keyvisual_item p span {
 display: inline-block;
 transform: scale(0);
 position: relative;
}
.keyvisual_item p span:not(:last-child) {
 margin-right: 1vw;
}

.keyvisual_item p spanはHTML上にはいませんでしたが、以下のJavascriptで一文字ずつspanで囲う処理を入れたあとで生きてきます。



Javascript


まずはHTML内でjQueryとanime.jsをロードしておきます。
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/animejs@3.1.0/lib/anime.min.js"></script>


全文はGithubをご覧いただくとして、ポイントをいくつか解説します。


文字を一文字ずつspanで囲い、アニメーションを適用させる
         //文字(p)を1個ずつspanで囲う
         $item.find('p').each(function (key, value) {
             var text = $(this).get(0).textContent;
             var textOut = '';
             var textArr = text.split('');
             var textNum = textArr.length;
             $.each(textArr, function (key, value) {
                 //ウインドウ内に収まるように文字サイズを調整
                 textOut += '<span style="font-size: ' + 70 / textNum + 'vw">' + value + '</span>';
             });
             $(this).empty();
             $(this).html(textOut);
         });

テキストを一文字ずつspanで囲うことで、一文字ずつアニメーションを伴って出現する・消える、という表現が可能になります。


anime.jsによるアニメーション構築
        //アニメーション
         //空タイムラインを定義し、addしていく方法が分かりやすくておすすめ
         const timeLine = anime.timeline({
             loop: true,
             autoplay: false // 停止状態でアニメなどを構築しておく
         });

         $item.each(function (key, value) {
             timeLine.add({
                 //文字のアニメーション
                 targets: $(value).find('p span').get(),
                 //1個おきに大きかったり小さかったり角度を付けたり
                 scale: function (el, index) {
                     return index % 2 ? [0, 1] : [0, 1.5]
                 },
                 rotate: function (el, index) {
                     return index % 2 ? [15, 15] : [-15, -15]
                 },
                 easing: 'easeOutCubic',
                 duration: 400,
                 //1文字ずつ200ミリ秒遅延させる
                 delay: anime.stagger(150)
             }).add({
                 //文字が全部表示されたら文字を消す
                 targets: $(value).find('p span').get(),
                 opacity: 0,
                 //1文字ずつ交互に上下に動く
                 top: function (el, index) {
                     return index % 2 ? '1em' : '-1em';
                 },
                 scale: '+=1.2',
                 easing: 'easeOutCubic',
                 duration: 600

             }, '-=100').add({
                 //ステージのフェードアウト
                 targets: $(value).get(0),
                 opacity: {
                     value: 0,
                     easing: 'linear'
                 },
                 duration: 400,
                 //順番を入れ替えて裏にもっていく
                 complate: function () {
                     $(this).append($(this).parent()).css('opacity', 1);
                 }
             });
         });
anime.jsにはtimelineという機能があり、timelineオブジェクトを定義し、そこにadd関数でつなげていくことで順繰りのアニメーションを作成することができます。JavascriptのPromiseと同等のものと考えると分かりやすいでしょう。

jQueryでこのような順番に実行されるアニメーションを作成するときは

・animate関数のコールバックでがんばる
・Deferredでがんばる

のどちらかになりますが、コールバックは地獄が待っていますしDeferredもコード量が増えてしまいます。

anime.jsはコード管理のしやすさという点でも扱いやすいライブラリです。

非公式ですが日本語翻訳されたドキュメントも分かりやすい。


まとめ


動画の場合は一部だけ差し替えたり文章を書き換えたりするのは難しいですが、画像と文字だけなら差し替えるのも簡単です。
ほかにはないオリジナルな表現をやってみたい方はぜひ参考にしてみてください!(もちろん当社へご依頼いただくのも大歓迎ですw)

ご相談・お問い合わせ

当社サービスについてのお問い合わせは下記までご連絡下さい。

お電話でのお問い合わせ

06-6121-7581 / 03-6415-8161