>
>
一文字ずつ下から出てくるテキスト

一文字ずつ下から出てくるテキスト

GSAPアニメーション
2026-05-17
2026-05-18
v3

スクロールして、指定の位置に来たら文字が一つづつ下から出てくるようなアニメーションをつけます。


1. クラス「anime-text」をウィジットにつけとく

2. 以下のCSS, JSを入れる

CSSコード

HTML
<style>
/* animation */
.anime-char-wrapper {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
}
.anime-char-inner {
  display: inline-block;
}
</style>

JSコード
(このコードの上にGSAP読み込みコードを入れてください。)

HTML
<script>
document.addEventListener('DOMContentLoaded', () => {
  gsap.registerPlugin(ScrollTrigger);

// --- animation text ---
  const animeElements = document.querySelectorAll('.anime-text');

  animeElements.forEach(container => {
    const titles = container.querySelectorAll('.elementor-heading-title');
    
    titles.forEach(title => {
      const wrapTextNodes = (el) => {
        const children = Array.from(el.childNodes);
        children.forEach(node => {
          if (node.nodeType === Node.TEXT_NODE) {
            const text = node.nodeValue;
            if (text.trim() === '') return;
            const fragment = document.createDocumentFragment();
            Array.from(text).forEach(char => {
              if (char.trim() === '') {
                fragment.appendChild(document.createTextNode(char));
              } else {
                const wrapper = document.createElement('span');
                wrapper.classList.add('anime-char-wrapper');
                
                const inner = document.createElement('span');
                inner.classList.add('anime-char-inner');
                inner.textContent = char;
                
                wrapper.appendChild(inner);
                fragment.appendChild(wrapper);
              }
            });
            el.replaceChild(fragment, node);
          } 
          else if (node.nodeType === Node.ELEMENT_NODE && node.tagName !== 'BR') {
            wrapTextNodes(node);
          }
        });
      };

      wrapTextNodes(title);
    });

    const chars = container.querySelectorAll('.anime-char-inner');

    gsap.fromTo(chars, 
      {
        yPercent: 115
      },
      {
        yPercent: 0,
        duration: 0.8,
        ease: "expo.out",
        stagger: 0.03,
        scrollTrigger: {
          trigger: container,
          start: "top 80%",
					toggleActions: "play none none reverse"
				}
      }
    );
  });
});
</script>

この記事をみんなにシェアしよう!!
Share!