icon

GSAPのScrollTriggerを使用してスクロールアニメーションを実装してみた

GSAPのScrollTrigger
投稿日時

更新日時

スクロールアクションを『GSAP』というJavaScriptライブラリの『ScrollTrigger』を使用して実装してみました。スクロールに合わせてテキストや画像が表示されます。

まずはデモサイトをご覧ください。

デモサイトはこちら

今回は、スクロールに合わせて、テキストを左から徐々に表示させたり、画像を下からフワッと表示させるアニメーションをかけてみました。


アニメーション毎のソースコード
テキストが左から右へ徐々に表示される

CSSの「clip-path」を使用して、「GSAP」の「ScrollTrigger」でclassの付け替えを行なっています。

HTML

/**html**/

<div class="ttl">
    <h2 class="ttl__clip">ScrollTrigger</h2>
    <span class="ttl__clip__line"></span>
</div>

Scss

/**scss**/

$color-bg:linear-gradient(133deg, rgba(250,246,246,1) 0%, rgb(223, 223, 223) 50%, rgb(196, 196, 196) 100%);
$color-bg02: linear-gradient(133deg, rgb(70, 70, 70) 0%, rgb(19, 19, 19) 50%, rgb(0, 0, 0) 100%);
$color-white: #fff;

@mixin media($breakpoint:md){
  @media #{map-get($breakpoint-up,$breakpoint)}{
    @content;
  }
}

$breakpoint-up: (
'bp760':'screen and(max-width:760px)',
)!default;


.ttl {
  display: table;
  margin-left: 5%;
  position: relative;
  &__clip {
    position: relative;
    display: inline-block;
    font-size: clamp(3rem, 4vw ,7rem);
    transition: clip-path .6s cubic-bezier(0.18, 0.06, 0.23, 1) .2s;
    clip-path: inset(0 100% 0 0);
    padding: 0 12px 8px 0;
    &__line {
      height: 2px;
      background-color: #000;
      width: 0;
      display: block;
      opacity: 0;
      position: absolute;
      bottom: 0;
      left: 0;
      &.slid__open {
        width: 100%;
        opacity: 1;
        transition: all .4s cubic-bezier(0.18, 0.06, 0.23, 1) 0s;
      }
    }
    &.slid__open {
      clip-path: inset(0);
    }
  }
}

JavaScript

繰り返し使えるように、「forEach」を使っています。

/**js**/

// テキストを徐々に表示させる
gsap.registerPlugin(ScrollTrigger);

const ttl__clips = document.querySelectorAll('.ttl__clip');

ttl__clips.forEach((ttl__clip, index) => {
  gsap.to(ttl__clip, {
    scrollTrigger: {
      trigger: ttl__clip,
      start: 'top-=300 center+=100',
      end: 'top top-=100',
    }
  });

  ScrollTrigger.create({
    trigger:ttl__clip,
    id: index+1,
    start: 'top center+=300',
    end: 'top top-=100',
    once: true,
    toggleClass: {
      targets: ttl__clip,
      className: 'slid__open',
    },
  });
});

const ttl__clip__lines = document.querySelectorAll('.ttl__clip__line');

ttl__clip__lines.forEach((ttl__clip__line, index) => {
  gsap.to(ttl__clip__line, {
    scrollTrigger: {
      trigger: ttl__clip__line,
      start: 'top center+=300',
      end: 'top top',
    }
  });

  ScrollTrigger.create({
    trigger:ttl__clip__line,
    id: index+1,
    start: 'top center+=300',
    end: 'top top',
    once: true,
    toggleClass: {
      targets: ttl__clip__line,
      className: 'slid__open',
    },
  });
});

テキストがスクロールに合わせて横に動く

スクロールに合わせて左右に横移動します。

HTML

/**html**/

 <section class="scroll">
    <div class="scroll__wrap">
      <p class="scroll__x">GSAPSCROLLGSAPSCROLLGSAPSCROLLGSAPSCROLLGSAPSCROLL</p>
    </div>
    <p class="fade__img"><img src="images/shapelined-_JBKdviweXI-unsplash.jpg" alt=""></p>
 </section>

Scss

/**scss**/

$color-bg:linear-gradient(133deg, rgba(250,246,246,1) 0%, rgb(223, 223, 223) 50%, rgb(196, 196, 196) 100%);
$color-bg02: linear-gradient(133deg, rgb(70, 70, 70) 0%, rgb(19, 19, 19) 50%, rgb(0, 0, 0) 100%);
$color-white: #fff;

@mixin media($breakpoint:md){
  @media #{map-get($breakpoint-up,$breakpoint)}{
    @content;
  }
}

$breakpoint-up: (
'bp760':'screen and(max-width:760px)',
)!default;

/*背景テキスト*/
.scroll {
  overflow: hidden;
  padding-top: 20%;
  padding-bottom: 20%;
  &__wrap {
    p {
      font-size: clamp(8rem, 15vw, 16rem);
      font-weight: 900;
      color: #ebe9e9;
      opacity: 0.1;
      -webkit-text-stroke: 1px #000;
    }
  }
}

JavaScript

/**js**/

// 背景テキストがスクロールに合わせて左へ動く
gsap.fromTo( '.scroll__x', {
    x: "-15.1797px",
},
{
  x: '-1603.18px',
  scrollTrigger: {
    trigger: '.scroll',
    start: 'top center+=300' ,
    end: 'bottom top', 
    scrub: 0.8,
  }
}
);

背景がスクロールに合わせて左から右へ広がって表示される

HTML

/**html**/

<div class="scroll__bg">
    <span class="scroll__cover"></span>
</div>

Scss

/**scss**/

$color-bg:linear-gradient(133deg, rgba(250,246,246,1) 0%, rgb(223, 223, 223) 50%, rgb(196, 196, 196) 100%);
$color-bg02: linear-gradient(133deg, rgb(70, 70, 70) 0%, rgb(19, 19, 19) 50%, rgb(0, 0, 0) 100%);
$color-white: #fff;

@mixin media($breakpoint:md){
  @media #{map-get($breakpoint-up,$breakpoint)}{
    @content;
  }
}

/*背景徐々に表示*/
.scroll__bg {
  position: relative;
  padding: 32px 0 48px;
  display: flex;
  justify-content: space-between;
  @include media(bp760) {
    display: block;
    padding: 15% 0;
  }
  .scroll__cover {
    position: absolute;
    top: 0;
    left: 0;
    z-index: -1;
    background: $color-bg02;
    transform-origin: left;
    width: 100%;
    height: 100%;
  }
  .fade__img {
    width: 50%;
    margin-right: 5%;
    margin-top: 10%;
    @include media(bp760) {
      margin-left: 5%;
      margin-right: 0;
      width: 90%;
    }
    img {
      width: 100%;
      height: auto;
    }
  }
}

JavaScript

/**js**/

// 背景が徐々に表示
gsap.fromTo('.scroll__cover', {
    x: "0",
    scaleX: 0,
    scaleY: 1,
},
{
  x: '0',
  scaleX: 1,
  scrollTrigger: {
    trigger: '.scroll__bg',
    start: 'top-=350 center+=100',
    end: 'bottom-=400 center+=100',
    scrub: 0.5,
    once: true,
  }
}
)

//下から画像フェードイン
const fadeUps = document.querySelectorAll('.fade__img');

fadeUps.forEach((fadeUp, index) => {
  gsap.fromTo(fadeUp, {
    autoAlpha: 0,
    y:20,
  },
  {
    autoAlpha: 1,
    y: 0,
    scrollTrigger: {
      trigger: fadeUp,
      start: 'top center+=100',
      end: 'top top',
      // toggleActions: "play pause resume reverse",
    }
  });
  ScrollTrigger.create({
    trigger: fadeUp,
    id: index+1,
    start: 'top center+=100',
    end: 'top top',
    once: true,
    // toggleActions: "play pause resume reverse",
  });
})

// 背景が徐々に表示
gsap.fromTo('.scroll__cover', {
    x: "0",
    scaleX: 0,
    scaleY: 1,
},
{
  x: '0',
  scaleX: 1,
  scrollTrigger: {
    trigger: '.scroll__bg',
    start: 'top-=350 center+=100',
    end: 'bottom-=400 center+=100',
    scrub: 0.5,
    once: true,
  }
}
)

//下から画像フェードイン
const fadeUps = document.querySelectorAll('.fade__img');

fadeUps.forEach((fadeUp, index) => {
  gsap.fromTo(fadeUp, {
    autoAlpha: 0,
    y:20,
  },
  {
    autoAlpha: 1,
    y: 0,
    scrollTrigger: {
      trigger: fadeUp,
      start: 'top center+=100',
      end: 'top top',
      // toggleActions: "play pause resume reverse",
    }
  });
  ScrollTrigger.create({
    trigger: fadeUp,
    id: index+1,
    start: 'top center+=100',
    end: 'top top',
    once: true,
    // toggleActions: "play pause resume reverse",
  });
})

テキストを1文字ずつしたから徐々に表示させる

HTML

/**html**/

  <div class="text__up">
    <span class="text__up__js">S</span>
    <span class="text__up__js">c</span>
    <span class="text__up__js">r</span>
    <span class="text__up__js">o</span>
    <span class="text__up__js">l</span>
    <span class="text__up__js">l</span>
    <span class="text__up__js">T</span>
    <span class="text__up__js">r</span>
    <span class="text__up__js">i</span>
    <span class="text__up__js">g</span>
    <span class="text__up__js">g</span>
    <span class="text__up__js">e</span>
    <span class="text__up__js">r</span>
  </div>
  <div class="text__up text__up__02">
    <span class="text__up__js">S</span>
    <span class="text__up__js">c</span>
    <span class="text__up__js">r</span>
    <span class="text__up__js">o</span>
    <span class="text__up__js">l</span>
    <span class="text__up__js">l</span>
    <span class="text__up__js">T</span>
    <span class="text__up__js">r</span>
    <span class="text__up__js">i</span>
    <span class="text__up__js">g</span>
    <span class="text__up__js">g</span>
    <span class="text__up__js">e</span>
    <span class="text__up__js">r</span>
  </div>

Scss

/**scss**/

//一文字ずつしたから表示
.text__up {
  display: flex;
  justify-content: center;
  margin: 15% auto 16px;
  overflow: hidden;
  span {
    display: block;
    font-size: 3.5rem;
    font-weight: bold;
    letter-spacing: 0.04em;
  }
  &__02 {
    margin: 0 auto 25%;
    span {
      font-size: 1.8rem;
    }
  }
}

JavaScript

/**js**/

//一文字ずつしたから表示
const text__ups = document.querySelectorAll('.text__up__js');

text__ups.forEach((text__up, i) => {
    gsap.fromTo(text__up, {
      opacity:0.1,
      y: '110%',
    },
    {
      opacity:1,
      y: 0,
      duration: 0.7,
      delay: i * 0.03,
      scrollTrigger: {
        trigger: '.text__up',
        start: 'top center+=300',
        end: 'top center+=300',
        once: true,
      }
    },
    )
}); 

画像を下からフワッとスケールしながら表示させる

HTML

/**html**/

  <div class="flower">
    <div class="flower__img flower__img__01 js-fadeup">
      <img src="images/pink.jpg" alt="">
    </div>
    <div class="flower__img flower__img__02 js-fadeup">
      <img src="images/yellow.jpg" alt="">
    </div>
    <div class="flower__img flower__img__03 js-fadeup">
      <img src="images/blue.jpg" alt="">
    </div>
  </div>

  <div class="grid__img">
    <div class="grid__img__item grid__img__item__01">
      <img src="images/hito01.jpg" alt="">
    </div>
    <div class="grid__img__item grid__img__item__02">
      <img src="images/hito02.jpg" alt="">
    </div>
    <div class="grid__img__item grid__img__item__03">
      <img src="images/hito03.jpg" alt="">
    </div>
    <div class="grid__img__item grid__img__item__04">
      <img src="images/hito04.jpg" alt="">
    </div>
    <div class="grid__img__item grid__img__item__05">
      <img src="images/hito05.jpg" alt="">
    </div>
  </div>

Scss

/**scss**/

/*画像が下から表示される*/
.flower {
  padding: 22% 0;
  background-color: $color-white;
  &__img {
    width: 58.04688%;
    position: relative;
    &:nth-child(even) {
      margin: 15% 0 15% auto;
    }
    &__02 {
      width: 41.25%;
    }
    &__03 {
      width: 48.125%;
      margin: {
        left: 8%;
      };
    }
  }
}

.grid__img {
  position: relative;
  display: block;
  background-color: $color-white;
  padding-top: 50%;
  padding-bottom: 20%;
  &__item {
    position: absolute;
    display: block;
    overflow: hidden;
    &::after {
      content: "";
      width: 100%;
      height: 102%;
      background-color: $color-white;
      position: absolute;
      top: 0;
      left: 0;
      transition: transform 1.5s cubic-bezier(0.215, 0.61, 0.355, 1) 0.5s;
      transform: translate3d(0, 0%, 0);
    }
    &.js-after {
      &::after {
        transform: translate3d(0, -102%, 0);
      }
      img {
        opacity: 1;
        transform: scale(1);
      }
    }
    img {
      width: 100%;
      height: 100%;
      display: block;
      opacity: 0;
      transform: scale(1.3);
      transition: transform 1.8s cubic-bezier(0.215, 0.61, 0.355, 1) 1s, opacity 1.2s cubic-bezier(0.473, 0.427, 0, 0.993) 0.8s;
      object-fit: cover;
    }
    &__01 {
      top: 0;
      left: 8.28125%;
      width: 25.46875%;
    }
    &__02 {
      width: 42.8125%;
      left: -9.0625%;
      top: 26.25%;
      height: 35%;
    }
    &__03 {
      width: 27.5%;
      left: 35%;
      top: 0;
      height: 74%;
    }
    &__04 {
      width: 25.46875%;
      right: 10.78125%;
      top: 6.58824%;
    }
    &__05 {
      width: 36.4%;
      right: 0;
      top: 33.17647%;
    }
  }
}

.js-fadeup {
  position: relative;
  overflow: hidden;
  &::after {
    content: "";
    width: 100%;
    height: 102%;
    background-color: $color-white;
    position: absolute;
    top: 0;
    left: 0;
    transition: transform 1.5s cubic-bezier(0.215, 0.61, 0.355, 1) 0.5s;
    transform: translate3d(0, 0%, 0);
  }
  &.js-after {
    &::after {
      transform: translate3d(0, -102%, 0);
    }
    img {
      opacity: 1;
      transform: scale(1);
    }
  }
  img {
    width: 100%;
    height: auto;
    display: block;
    opacity: 0;
    transform: scale(1.3);
    transition: transform 1.8s cubic-bezier(0.215, 0.61, 0.355, 1) 1s, opacity 1.2s cubic-bezier(0.473, 0.427, 0, 0.993) 0.8s;
  }
  }

JavaScript

/**js**/

// 画像を下から表示させる
const jsFadeUps = document.querySelectorAll('.js-fadeup');

jsFadeUps.forEach((jsFadeUp, index) => {
  gsap.to(jsFadeUp, {
    scrollTrigger: {
      trigger: jsFadeUp,
      start: 'top-=200 bottom',
      end: 'bottom top',
      scrub: true,
    }
  });

  ScrollTrigger.create({
    trigger: jsFadeUp,
    start: 'top-=200 bottom',
    end: 'bottom top',
    id: index+1,
    once: true,
    toggleClass: {
      targets: jsFadeUp,
      className: 'js-after',
    }
  })
})

const gridItems = document.querySelectorAll('.grid__img__item');

gridItems.forEach((gridItems, index) => {
  gsap.to(gridItems, {
    scrollTrigger: {
      trigger: gridItems,
      start: 'top bottom',
      end: 'bottom top',
      scrub: true,
    }
  });

  ScrollTrigger.create({
    trigger: gridItems,
    start: 'top bottom',
    end: 'bottom top',
    id: index+1,
    once: true,
    toggleClass: {
      targets: gridItems,
      className: 'js-after',
    }
  })
})