【世界一簡単】ポップアップアニメーション作成【デモ付き】

りょーすけ
りょーすけ

WEBサイトでよく見かける要素が登場するアニメーション
どうやって実装するんだ?

GSAP MAN
GSAP MAN

GSAPの出番だ!

よくWebサイトで見かけるポップアップアニメーション

あるだけでサイトがリッチになる表現ですが実装方法の最適解をお教えします。

CodePenによるデモ

まずはデモを見てもらいましょう。しばらくスクロールするとカード型の要素がポップアップして登場します

See the Pen Untitled by りょーすけ (@s_ryosuke_1242) on CodePen.

もう一度再生したいときは右下の『Return』ボタンから可能です

アニメーションライブラリGSAPを事前にダウンロード

このリッチなアニメーションのタネはGSAPを用いているところです

GSAPの概要は以下の記事を参考にしてください

またデモ上ではGSAPのScrollTriggerというプラグインを用いています。概要は以下の記事から

まずは上記の記事を参考に忘れずGSAPとScrollTriggerをダウンロードしておいてください。

準備が出来たらHTML/CSS/JSの記述して実装するだけです

HTML アニメーション用のクラス名を付与するだけ

上からタイトル→横並びのカード→メディア型カード→ボタン複数横並び→アイテム横並び8つのシンプルな構成です

アニメーションをつけたい要素に対してはそれぞれjs-fadeIn js-popUp js-popUps というクラス名をつけています

<main class="container">
    <h2 class="title js-fadeIn">タイトル</h2>
    <div class="cards js-popUps">
        <div class="card">
            <h3 class="heading">見出し</h3>
            <p class="text">
                いつは直接じっとこんな留学家という事の上にありでな。いくら十月に詐欺心ももしその関係ないなまでがしでいうがも拡張伺いなますば、それほどには含またますなまし。学校としでしょのもすでに以前にもうないですん。とうてい大森さんを関係慣例どう講演を来ん模範そんな手私か品評をという肝矛盾うないだっなて、この一生も私か本位校長がなっが、大森さんののが先生の私にどうかお議論とありがそれ肴で不謝罪を申しようにもうご盲動からしたたが、ちっともどうしても準備を教えんているです事を受けでしょた。またしたがって不学校に至るのも全く馬鹿とかかりますが、その責任をも眺めないてという社会にありから来るありう。
            </p>
            <a class="btn" href="./">ボタン</a>
        </div>
        <div class="card">
            <h3 class="heading">見出し</h3>
            <p class="text">
                その以上他のためこの人格もあなたごろが欠けなかと岡田さんに破るありです、仲間の一番なというご学習ですますでして、中学の所に願と時間だけの衣食を場合落ちから出して、まだの今をあってそのためがもうしですたと亡びるう事あって、よかっですますてそれだけお概念あるありのますないた。あるいは通りか美味か創作に書いたば、結果上人に眺めるしいるんためをお話の時間にありありたく。平生がも恐らく威張ってさませたありなけれて、とにかくとうてい来で教育はこうないん事まし。
            </p>
            <a class="btn" href="./">ボタン</a>
        </div>
    </div>
    <div class="media js-popUp">
        <img class="media__img" width="1080" height="720" src="https://ryo-sukeblog.net/wp-content/uploads/2023/02/scrub-animation.webp" alt="">
        <p class="media__text">
            しかし今相当をなりてもいるた訳たて、鼻がは、どうか私かきまっとしられでですあてるれるなましと失っから、徳義はしばいたなけれ。ついに幾分はひょろひょろ秋刀魚として切っでしば、みんなにも大体上くらい私の小発展は深い云いいないない。誰はどうしても周旋ののでお生活は云うていませただろんが、一十の画へそうつからしくって通用たて、もしくはその職業の珍にできるれると、あなたかを皆の火事を接近のしているた方ますたと相違申して存在迂得るましで。個人にまた大森さんにまた実際したのますますた。
        </p>
    </div>
    <div class="btns js-popUps">
        <a class="btn btn--larger" href="">ボタン</a>
        <a class="btn btn--larger" href="">ボタン</a>
    </div>
    <div class="items js-popUps">
        <div class="item">01</div>
        <div class="item">02</div>
        <div class="item">03</div>
        <div class="item">04</div>
        <div class="item">05</div>
        <div class="item">06</div>
        <div class="item">07</div>
        <div class="item">08</div>
    </div>
</main>

CSS / アニメーションの下準備をしておこう

@import url('https://fonts.googleapis.com/css2?family=Zen+Maru+Gothic:wght@500;700;900&display=swap');

*{
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}
body{
    background-color: #333;
    font-family: 'Zen Maru Gothic',sans-serif;
}
a{
    text-decoration: none;
    color: #111;
}
.container{
    width: 100%;
    height: auto;
    padding: 100vh 40px 120px;
}
.title{
    font-size: 40px;
    color: white;
    text-align: center;
    font-family: 'Zen Maru Gothic', sans-serif;
}
.cards{
    width: 100%;
    max-width: 1024px;
    display: flex;
    justify-content: space-between;
    margin: 80px auto 0;
}
.card{
    width: 48%;
    border-radius: 10px;
    background-color: #fff;
    padding: 20px 40px;
    display: flex;
    flex-direction: column;
    align-items: center;
}
.heading{
    font-size: 32px;
    color: #3CB371;
    text-align: center;
}
.text{
    font-size: 18px;
    line-height: 1.8;
    font-weight: 500;
    margin: 20px 0;
}
.btn{
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    max-width: 200px;
    padding: 10px;
    background-color: #3CB371;
    color: white;
    margin: 20px auto 0;
    font-size: 18px;
    border-radius: 4px;
    margin-top: auto;
}
.media{
    width: 100%;
    max-width: 1024px;
    height: auto;
    padding: 20px;
    background-color: #fff;
    margin: 80px auto 0;
    border-radius: 10px;
    display: flex;
}
.media__img{
    display: block;
    width: 50%;
    height: auto;
    object-fit:cover;
}
.media__text{
    width: 50%;
    padding: 10px;
    line-height: 2;
}
.btns{
    max-width: 1024px;
    display: flex;
    gap:40px;
    margin: 80px auto 0;
    justify-content: center;
}
.btn--larger{
    width: 100%;
    padding: 20px;
    max-width: initial;
}
.items{
    max-width: 1024px;
    width: 100%;
    margin: 80px auto;
    display: flex;
    justify-content: space-between;
    gap: 20px;
}
.items .item:nth-of-type(odd){
    background-color: #3CB371;
}
.items .item:nth-of-type(even){
    background-color: #fff;
    color: #3CB371;
}
.item{
    width: 100%;
    color: white;
    border-radius: 5px;
    height: auto;
    aspect-ratio: 1/1;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: bold;
    font-size: 18px;
}

/*アニメーション下準備*/
.js-fadeIn{
    opacity: 0;
    visibility: hidden;
}
.js-popUp{
    transform: scale(.9);
    opacity: 0;
    visibility: hidden;
}
.js-popUp > div{
    transform: scale(.9);
    opacity: 0;
    visibility: hidden;
}

127行目まではレイアウトを整えるだけのスタイル設定です

大事なのは129行目以降

それぞれ予めopacityやvisibilityを指定して非表示

transform:scale(0.9);で対象となる要素を小さくしています

JavaScript / GSAPメイン

/*フェードインアニメーション*/
gsap.utils.toArray('.js-fadeIn').forEach(target => {
    gsap.to(target,{autoAlpha:1,scrollTrigger:{
        trigger:target,
        start:'bottom center+=100'//要素の下端が画面真ん中より100px下に到達したら発火
    }})
});
/*連続ポップインアップアニメーション*/
gsap.utils.toArray('.js-popUps').forEach(target => {
    var targets = target.querySelectorAll(':scope > *');//targetの直下に要素を取得
    gsap.fromTo(targets,{scale:.9,autoAlpha:0},{scale:1,autoAlpha:1,
        ease:"back.out(1.7)",
        stagger:{
            each:.08
        },
        scrollTrigger:{
            trigger:target,
            start:'top center'
        }
    })
});
/*ポップインアニメーション*/
gsap.utils.toArray('.js-popUp').forEach(target => {
    gsap.to(target,{scale:1,autoAlpha:1,
        ease:"back.out(1.7)",
        scrollTrigger:{
        trigger:target,
        start:'bottom bottom'
    }})
});

gsap.utils.toArray();document.querySelectorAll();と同等の意味です

性能の差は感じられませんが、ほんの少しだけ文字数が少ないため、最近gsapを使用しているときはgsap.utils.toArray();を採用しています

.forEachを使っていることから分かるように、複数要素ポップアップアニメーションさせる対象があっても対応できるようにしています

イメージは.forEachで各要素に対してアニメーションを定義していると思っていただければ理解しやすいと思います

ScrollTriggerの説明は【初心者向け】GSAPのScrollTriggerの使い方を解説!【JavaScriptの知識ほぼ不要】でも説明していますが

trigger:target,

triggerプロパティではアニメーションのトリガーとなる要素を定義

start:'bottom center+=100'//要素の下端が画面真ん中より100px下に到達したら発火

startはトリガーさせる位置を定義しています。

上記の場合‘対象となる要素の下端(bottom)が画面縦幅の真ん中(center)’の位置から下に100px位置するラインに差し掛かったら発火させるという意味になっています

stagger:{
  each:.08//0.08秒差でアニメーション作動
},

連続ポップアップアニメーションで使用されているstaggerは時間差でアニメーションさせることが可能です

まとめ

GSAPとGSAPのプラグインであるScrollTriggerを使用することで要素が画面内に入ったらアニメーションを作動させることが可能となります。

この手のライブラリは他にもありますが、ScrollTriggerの良いところは%やpx単位で位置を指定できるところです。

しかも簡単に直感的に指定できるため実務でもかなり重宝しています

ぜひ皆さんも僕のブログを参考にGSAP導入を検討してみてください