<h2 class="scroll-anim-28" id="js-scroll-anim-28"><span class="scroll-anim-28__main"><span>H</span><span>E</span><span>A</span><span>D</span><span>I</span><span>N</span><span>G</span><span>2</span><span>8</span></span><span class="scroll-anim-28__sub"><span></span><span></span><span></span><span></span><span></span></span></h2>
h2.scroll-anim-28#js-scroll-anim-28
  span.scroll-anim-28__main
    - for (var i = 0; i < main.length; i++)
      span #{ main[i] }
  span.scroll-anim-28__sub
    - for (var j = 0; j < sub.length; j++)
      span #{ sub[j] }
{
  "main": "HEADING28",
  "sub": "サブ見出し"
}
  • Content:
    $BLOCK_NAME: '.scroll-anim-28';
    
    // 変数
    
    #{ $BLOCK_NAME } {
      display: flex;
      flex-direction: column;
      gap: 8px;
      align-items: flex-start;
      color: #454545;
      visibility: hidden;
      &.--anim-start {
        visibility: visible;
      }
    
      &__main {
        display: block;
        font-size: 32px;
        font-weight: bold;
        line-height: 1;
    
        > span {
          // display: inline-block;
          display: none;
          line-height: 1;
        }
    
        &::after {
          content: '';
          background: #454545;
          width: 4px;
          height: 28px;
          margin-left: 3px;
          display: inline-block;
          vertical-align: top;
          animation: blink 1s linear infinite both;
        }
      }
    
      &__sub {
        display: block;
        font-size: 20px;
        line-height: 1;
        background: #fef6b5;
        border: 1px solid #454545;
        padding: 3px 3px 1px;
        font-weight: bold;
    
        > span {
          // display: inline-block;
          display: none;
          line-height: 1;
        }
    
        &::after {
          content: '';
          background: #454545;
          width: 3px;
          height: 18px;
          margin-left: 2px;
          display: inline-block;
          vertical-align: top;
          animation: blink 1s linear infinite both;
        }
      }
    }
    
    @keyframes blink {
      0% {
        opacity: 0;
      }
      1% {
        opacity: 1;
      }
      49% {
        opacity: 1;
      }
      50% {
        opacity: 0;
      }
      100% {
        opacity: 0;
      }
    }
    
  • URL: /components/raw/scroll-anim28/scroll-anim28.scss
  • Filesystem Path: src/components/scroll-anims/scroll-anim28/scroll-anim28.scss
  • Size: 1.3 KB
  • Content:
    'use strict';
    
    import { gsap } from 'gsap';
    import { ScrollTrigger } from 'gsap/ScrollTrigger';
    gsap.registerPlugin(ScrollTrigger);
    
    export const scrollAnim28 = () => {
      const anim = new Anim28('js-scroll-anim-28');
      anim.init();
    };
    
    class Anim28 {
      el: HTMLElement;
      mainEls: NodeListOf<HTMLElement>;
      subEls: NodeListOf<HTMLElement>;
      constructor(elId: string) {
        this.el = document.getElementById(elId);
        if (!this.el) return;
        this.mainEls = this.el.querySelectorAll('.scroll-anim-28__main span');
        this.subEls = this.el.querySelectorAll('.scroll-anim-28__sub span');
      }
    
      /**
       * 初期化
       */
      init(): void {
        if (!this.el) return;
        this.scrollHandler();
      }
    
      /**
       * スクロール連動のイベント設定
       */
      scrollHandler(): void {
        const self = this;
        gsap.to(this.mainEls, {
          display: 'inline-block',
          delay: 0.2,
          stagger: {
            each: 0.1,
          },
          scrollTrigger: {
            trigger: this.el,
            start: 'top center',
            // markers: true,
          },
          onStart() {
            self.el.classList.add('--anim-start');
            gsap.to(self.subEls, {
              display: 'inline-block',
              stagger: {
                each: 0.1,
              },
            });
          },
        });
      }
    }
    
  • URL: /components/raw/scroll-anim28/scroll-anim28.ts
  • Filesystem Path: src/components/scroll-anims/scroll-anim28/scroll-anim28.ts
  • Size: 1.3 KB