【GSAP】3段階のスライド式の扉実装方法の紹介【数行で可能】

りょーすけ
りょーすけ

お洒落な和のサイトで使われるようなスクラブアニメーションない??

GSAP MAN
GSAP MAN

僕の出番だね!お任せあれ

和といえば襖。襖と言えばスライド式の扉。

ということで今回はアニメーションライブラリGSAPを用いて和のサイトで使用されるようなスクラブアニメーションについてご紹介します。

動きを確認 – デモ

まずは動きを見ていただきましょう

See the Pen 3stage Slide Door by りょーすけ (@s_ryosuke_1242) on CodePen.

しばらくスクロールすると枠線で囲まれたセクションに到達すると画面が固定されるはずです

さらにスクロールを続けると右に配置されている3枚のスライドが左へ移動します

3枚とも移動が完了したら枠線で囲まれたセクションを抜け下に進みます

HTML

次にHTMLを見てみましょう

<div class="container">
    <div class="spacer"></div>
    <div class="container__inner">
        <span class="heading-sub">3stage sliding door width <span>GSAP</span></span>
        <h2 class="heading">3段階 スライド式ドア</h2>
        <div class="lists">
            <div class="text-wrap">
                <p class="text">魏・呉・蜀</p>
                <p class="scroll-induction">
                    スクロールしてみてね😉
                </p>
            </div>
            <div class="list feature_1 js-move-target">
                <div class="list-title">
                    <span class="list-title__sub">Feature 1</span>
                    <h3 class="list-title__main">魏</h3>
                </div>
            </div>
            <div class="list feature_2 js-move-target">
                <div class="list-title">
                    <span class="list-title__sub">Feature 2</span>
                    <h3 class="list-title__main">呉</h3>
                </div>
            </div>
            <div class="list feature_3 js-move-target">
                <div class="list-title">
                    <span class="list-title__sub">Feature 3</span>
                    <h3 class="list-title__main">蜀</h3>
                </div>
            </div>
        </div>
    </div>
    <div class="spacer"></div>
</div>

行数が多いため複雑に見えますが構造は単純です

今回のスクラブアニメーションにかかわるのはlists要素とその中にある3つのlist要素です

それでも「分かりにくい!」という方はtext-wrapの箇所を消せば構造が見えてくるのではないでしょうか

SCSS

次にCSSです

78行目まではスクラブアニメーションには特に関係のない箇所の見た目を整える記述です

大事なのは81行目から

*{
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}
body{
    background-color: #F7E9E1;
}
.spacer{
    width: 100%;
    height: 80vh;
}
.container{
    width: 100%;
    &__inner{
        width: 100%;
        max-width: 1440px;
        height: 100vh;
        margin: 0 auto;
        border: 1px solid #ccc;
        display: flex;
        flex-direction: column;
        align-items: center;
    }
}
.heading{
    font-size: 40px;
    text-align: center;
}
.heading-sub{
    font-size: 24px;
    text-align: center;
    font-family: serif;
    display: block;
    margin: 0 auto;
    span{
        color: green;
        font-weight: bold;
    }
}
.list-title{
    width: 80px;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 10px 0;
    &__main{
        margin-top: auto;
        writing-mode: vertical-lr;
    }
    &__sub{
        writing-mode: vertical-lr;
        font-family: serif;
        font-weight: bold;

    }
}
.text-wrap{
    width: 100%;
    height: 100%;
    display: flex;
    align-items: bottom;
}
.text-wrap .text{
    font-size: 40px;
    font-family: serif;
    font-weight: 900;
    writing-mode: vertical-lr;
    margin-top: auto;
}
.text-wrap .scroll-induction{
    font-size: 18px;
    font-family: serif;
    font-weight: 900;
    writing-mode: vertical-lr;
    margin-top: auto;
}
/*ここまでは見た目を整える部分*/

/*ここから下が重要*/
.lists{
    width: 100%;
    margin-top: 80px;
    height: 100%;
    position: relative;//忘れないように注意
    overflow: hidden;//外側にはみ出た分を非表示
    .feature_1{
        background-color: #eee2d3;
        left: 0;//この値で各扉の位置をずらす
    }
    .feature_2{
        background-color: #c39c89;
        left: 80px;//この値で各扉の位置をずらす
    }
    .feature_3{
        background-color: #e7b09f;
        left: 160px;//この値で各扉の位置をずらす
    }
}

.list{
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    border-top: 1px solid #ccc;
    transform: translateX(calc(100% - 240px));//予め右に配置
}

.lists要素の86行目にあるposition: relative;によって.lists要素を親要素と定義します

.lists要素の中にある.list要素に対してそれぞれ.feature_1.feature_2、.feature_3クラスを付与しており各々leftプロパティを付与しておきます

これによって親要素.listsを基準に左から右へ指定した値をずらします。これで各扉のズレを表現可能です

108行目の記述

transform: translateX(calc(100% - 240px));//予め右に配置

transformを使ってその要素自身の大きさ分-240px分右に予め配置しておきます

さらには87行目にあるoverflow: hidden;によってはみ出た分を非表示にしています

これで準備が完了しました。分からないところは実際に値を変更してみると意味が理解できるかと思います

JavaScript

いよいよ核となるJavaScriptです

毎度のごとく忘れずにCDN等でGSAPのダウンロードをしておきましょう

ダウンロード方法を知っている方はこちら

分からない方はこちらから

  const target = document.querySelectorAll('.js-move-target');//3枚の扉を取得
  const tl = gsap.timeline();//連続でアニメーションを流すタイムラインを定義
  tl
  .to(target[0],{x:0,duration:3})//1枚目の扉が元の位置に移動
  .to(target[1],{x:0,duration:3})//2枚目の扉が元の位置に移動
  .to(target[2],{x:0,duration:3})//3枚目の扉が元の位置に移動

  ScrollTrigger.create({
      trigger:'.container__inner',//トリガーとなる要素を指定
      start:'top top',//トリガーの発火スタート位置
      end:'+=5000',//トリガーの発火スタート位置
      pin:true,//トリガーに到達したら画面固定
      animation:tl,//トリガーに到達した時に流すアニメーション
      scrub:.5,//慣性力を指定
  })

「超スッキリしてる!!笑」という印象を皆さん持ったはずです

解説は全行にコメントを付けているので、もはや不要なのですがポイントは13行目のanimationプロパティです

これはスクロール位置がtriggerプロパティに到達した時に流すアニメーションを指定することが可能です

他はscrubの値を小さくすることでスクロールに対するレスポンスが良くなり反対に値を大きくするとスクロールした時の余韻が発生するようになります

まとめ

以上となります。大胆なアニメーションの割にはJSの記述が思ったよりも短くなったのが驚きでしたね。

Vanilla JSの知識が必要となるところはdocument.querySelectorAllによる要素の取得

target[0],target[1],target[2]・・・のような配列の概念のみです

いろんな値を弄って挙動を確かめることで理解が促進されます

ぜひ皆さんもチャレンジしてみてください。最後までご覧いただきありがとうございます!またね~!