<div class="scroll-anim-27" id="js-scroll-anim-27">
    <div class="scroll-anim-27__main">
        <div class="scroll-anim-27__text">
            <div>HEADING</div>
        </div>
        <div class="scroll-anim-27__decoration"></div>
    </div>
    <div class="scroll-anim-27__sub">見出し</div>
</div>
#js-scroll-anim-27.scroll-anim-27
  .scroll-anim-27__main
    .scroll-anim-27__text
      div HEADING
    .scroll-anim-27__decoration

  .scroll-anim-27__sub 見出し
{
  "text": "テキストが入ります。テキストが入ります。テキストが入ります。"
}
  • Content:
    $BLOCK_NAME: '.scroll-anim-27';
    
    // 変数
    $anim_27_grad: linear-gradient(to right, rgba(18, 86, 179, 0.9), rgba(255, 25, 82, 0.9));
    
    #{ $BLOCK_NAME } {
      display: grid;
      gap: 20px;
      justify-items: center;
      font-weight: bold;
      text-align: center;
      letter-spacing: 0.25em;
    
      &__main {
        position: relative;
      }
    
      &__text {
        position: relative;
        opacity: 0;
        transition: opacity 0.2s 0.55s;
        @at-root #{ $BLOCK_NAME }.--animated & {
          opacity: 1;
        }
        div {
          font-size: 32px;
          line-height: 1;
          background: $anim_27_grad;
          -webkit-text-fill-color: transparent;
          -webkit-background-clip: text;
          @at-root #{ $BLOCK_NAME }.--animated & {
            animation: 0.12s ease-in-out 1s forwards;
          }
          &:nth-child(n + 2) {
            position: absolute;
            top: 0;
            left: 0;
          }
          &:nth-child(1) {
            -webkit-mask-image: linear-gradient(black 0%, black 45%, transparent 45%);
            @at-root #{ $BLOCK_NAME }.--animated & {
              animation-name: scrollAnim27Main1;
            }
          }
          &:nth-child(2) {
            -webkit-mask-image: linear-gradient(transparent 0%, transparent 45%, black 45%, black 55%, transparent 55%);
            @at-root #{ $BLOCK_NAME }.--animated & {
              animation-name: scrollAnim27Main2;
              animation-delay: 1.1s;
            }
          }
          &:nth-child(3) {
            -webkit-mask-image: linear-gradient(transparent 0%, transparent 55%, black 55%, black 65%, transparent 65%);
            @at-root #{ $BLOCK_NAME }.--animated & {
              animation-name: scrollAnim27Main3;
              animation-delay: 1.1s;
            }
          }
          &:nth-child(4) {
            -webkit-mask-image: linear-gradient(transparent 0%, transparent 65%, black 65%);
            @at-root #{ $BLOCK_NAME }.--animated & {
              animation-name: scrollAnim27Main4;
            }
          }
        }
      }
    
      &__decoration {
        position: absolute;
        inset: -10px -40px;
        overflow: hidden;
        div {
          width: 100%;
          height: 20%;
          border-radius: 9999px;
          background: $anim_27_grad;
          transition: transform 0.6s cubic-bezier(0.4, 0.26, 0.15, 0.99);
          &:nth-child(1),
          &:nth-child(2),
          &:nth-child(4) {
            transform: translateX(101%);
            @at-root #{ $BLOCK_NAME }.--animated & {
              transform: translateX(-101%);
            }
          }
          &:nth-child(3),
          &:nth-child(5) {
            transform: translateX(-101%);
            @at-root #{ $BLOCK_NAME }.--animated & {
              transform: translateX(101%);
            }
          }
          &:nth-child(1) { transition-delay: 0.3s; }
          &:nth-child(2) { transition-delay: 0.2s; }
          &:nth-child(3) { transition-delay: 0.5s; }
          &:nth-child(4) { transition-delay: 0.3s; }
          &:nth-child(5) { transition-delay: 0.4s; }
        }
      }
    
      &__sub {
        position: relative;
        font-size: 14px;
        opacity: 0;
        transition: opacity 0.22s 0.4s;
        @at-root #{ $BLOCK_NAME }.--animated & {
          opacity: 1;
        }
        &::before,
        &::after {
          content: '';
          position: absolute;
          top: 0;
          bottom: 0;
          margin: auto;
          display: block;
          width: 6px;
          height: 1px;
          background: #000;
          transform: scaleX(0);
          @at-root #{ $BLOCK_NAME }.--animated & {
            animation: scrollAnim27Border 0.6s ease-out 0.6s forwards;
          }
        }
        &::before {
          left: calc(100% + 8px);
          transform-origin: left center;
        }
        &::after {
          right: calc(100% + 8px);
          transform-origin: right center;
        }
      }
    }
    
    @keyframes scrollAnim27Border {
      0% {
        transform: scaleX(0);
      }
      60% {
        transform: scaleX(20);
      }
      80% {
        transform: scaleX(0.5);
      }
      90% {
        transform: scaleX(1.5);
      }
      100% {
        transform: scaleX(1);
      }
    }
    
    @keyframes scrollAnim27Main1 {
      0% {
        transform: translateX(0);
        opacity: 1;
      }
      25% {
        transform: translateX(-15%);
        opacity: 0;
      }
      50% {
        transform: translateX(-30%);
        opacity: 1;
      }
      75% {
        transform: translateX(-15%);
        opacity: 0;
      }
      100% {
        transform: translateX(0);
        opacity: 1;
      }
    }
    
    @keyframes scrollAnim27Main2 {
      0% {
        transform: translateX(0);
        opacity: 1;
      }
      25% {
        transform: translateX(30%);
        opacity: 0;
      }
      50% {
        transform: translateX(60%);
        opacity: 1;
      }
      75% {
        transform: translateX(30%);
        opacity: 0;
      }
      100% {
        transform: translateX(0);
        opacity: 1;
      }
    }
    
    @keyframes scrollAnim27Main3 {
      0% {
        transform: translateX(0);
        opacity: 1;
      }
      25% {
        transform: translateX(-30%);
        opacity: 0;
      }
      50% {
        transform: translateX(-60%);
        opacity: 1;
      }
      75% {
        transform: translateX(-30%);
        opacity: 0;
      }
      100% {
        transform: translateX(0);
        opacity: 1;
      }
    }
    
    @keyframes scrollAnim27Main4 {
      0% {
        transform: translateX(0);
        opacity: 1;
      }
      25% {
        transform: translateX(15%);
        opacity: 0;
      }
      50% {
        transform: translateX(30%);
        opacity: 1;
      }
      75% {
        transform: translateX(15%);
        opacity: 0;
      }
      100% {
        transform: translateX(0);
        opacity: 1;
      }
    }
    
  • URL: /components/raw/scroll-anim27/scroll-anim27.scss
  • Filesystem Path: src/components/scroll-anims/scroll-anim27/scroll-anim27.scss
  • Size: 5.1 KB
  • Content:
    'use strict';
    
    import { gsap } from 'gsap';
    import { ScrollTrigger } from 'gsap/ScrollTrigger';
    gsap.registerPlugin(ScrollTrigger);
    
    export const scrollAnim27 = () => {
      const anim = new Anim27('js-scroll-anim-27');
      anim.init();
    }
    
    class Anim27 {
      el: HTMLElement;
      constructor(elId: string) {
        this.el = document.getElementById(elId);
      }
    
      /**
       * 初期化
       */
      init(): void {
        if (!this.el) return;
        this.setElements();
        this.scrollHandler();
      }
    
      /**
       * 要素設定
       */
      setElements() {
        // メインテキストを複製
        const textEl = this.el.querySelector('.scroll-anim-27__text');
        const textElChild = textEl.children[0];
        for (let i = 0; i < 3; i++) {
          const cloneEl = textElChild.cloneNode(true);
          textEl.appendChild(cloneEl);
        }
        // 装飾要素を挿入
        const decorationEl = this.el.querySelector('.scroll-anim-27__decoration');
        for (let i = 0; i < 4; i++) {
          const el = document.createElement('div');
          decorationEl.appendChild(el);
        }
      }
    
      /**
       * スクロール連動のイベント設定
       */
      scrollHandler(): void {
        ScrollTrigger.create({
          trigger: this.el,
          start: 'top 70%',
          onEnter: self => {
            // 「is-animated」クラスを付与
            this.el.classList.add('--animated');
            self.kill();
          }
        });
      }
    }
    
  • URL: /components/raw/scroll-anim27/scroll-anim27.ts
  • Filesystem Path: src/components/scroll-anims/scroll-anim27/scroll-anim27.ts
  • Size: 1.4 KB