【GSAP】テキストの時間差出現を利用したローディング演出を実装

今回はJavaScriptのアニメーションライブラリ、『GSAP』を用いてテキストの時間差出現を利用したローディング演出を実装してみました。

コピペしてすぐに実装できるようにCodePenによるデモを用意しています。お洒落なサイトなどでも使えそうなものとなっています。ぜひ最後までご覧いただけると嬉しいです。

1.実装イメージ

実装イメージは以下の通りです。

See the Pen gsap-loading1 by りょーすけ (@s_ryosuke_1242) on CodePen.

注意点としては予め、CDNでプラグインをダウンロードしておきましょう。

CDNはコチラ

必要なファイルは『gsap.min.js』です。

2.HTML

HTMLはコチラの通りになっています。比較的シンプルですね

<div class="loading-wrap">
  <div class="text-wrap">
    <span class="split">Loading</span>
  </div>
  <div class="reveal-1"></div>
  <div class="reveal-2"></div>
</div>
<div class="mv">
  <video muted autoplay playsinline loop class="routingByBreakpoint">
    <source data-src="https://ryo-sukeblog.net/wp-content/uploads/movie/coffee_pc.mp4" data-query="pc">
    <source data-src="https://ryo-sukeblog.net/wp-content/uploads/movie/coffee_sp.mp4" data-query="mobile">
  </video>
  <div class="mv__body">
    <div class="text-wrap">
      <h1 class="split">Lorem</h1>
    </div>
    <div class="text-wrap">
      <h2 class="split">ipsum dolor sit amet</h2>
    </div>
    <div class="text-wrap">
      <p class="split"> consectetur adipiscing elit, sed do eiusmod tempor</p>
    </div>
    <div class="text-wrap">
      <p class="split">incididunt ut labore et dolore magna aliqua</p>
    </div>
  </div>
</div>

3.CSS

次にCSSです。

*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
html,body,main,section{
    width: 100%;
}
.loading-wrap{
    width: 100%;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    top: 0;
}
.text-wrap{
    overflow: hidden;
}
.loading-wrap .text-wrap .split{
    display: block;
    font-size: 40px;
    font-weight: bold;
    color: #f7e3af;
    position: relative;
    z-index: 20;
}
.text-wrap .split span{
    display: inline-block;
}
.reveal-1,.reveal-2{
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
}
.reveal-1{
    background-color:#333;
    z-index: 30;
}
.reveal-2{
    background-color: #70372c;
    z-index: 10;
}
.mv{
    width: 100%;
    height: 100vh;
    position: relative;
}
.mv video{
    width: 100%;
    height: 100%;
    object-fit: cover;
    position: relative;
    z-index: -1;
}
.mv .mv__body{
    position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	-webkit-transform: translate(-50%, -50%);
	-ms-transform: translate(-50%, -50%);
    z-index: -1;
    color: white;
}
.mv .mv__body h1{
    font-size:40px;
}
.mv .mv__body h2{
    font-size:32px;
}
.mv .mv__body h3{
    font-size:28px;
}

4.JavaScript

次にJavaScriptです

var defaultQueryList = {
	mobile: matchMedia("(max-width: 1279px"),
	pc: matchMedia("(min-width: 1280px)")
}

function routingByBreakpoint(sourceList) {
	for(var i = 0, l = sourceList.length; i < l; i++){
		var source = sourceList[i];

		if(!(source.dataset.query && defaultQueryList[source.dataset.query] && source.dataset.src)) continue;
		if(!(defaultQueryList[source.dataset.query].matches)) continue;

		var newSource = document.createElement("source");
		newSource.src = source.dataset.src;

		source.parentElement.appendChild(newSource);
	}
}

//txt分割
function txtSplit(el){//https://sinciate.co.jp/media/2999/
    var content = el.textContent;
    var text = content.trim();
    var newHtml = "";

    text.split("").forEach(function(v) {
        newHtml += "" + v + "";
    });
    el.innerHTML = newHtml;
}

window.addEventListener('load',(e)=>{
  Splittargets = document.querySelectorAll('.split');
  for (let i = 0; i < Splittargets.length; i++) {
	txtSplit(Splittargets[i]);
  }


  var tl = gsap.timeline();
  tl
  .to('.reveal-1',{y:'-100%'})
  .from('.loading-wrap .split span',{y:'100%',duration:.5,stagger:.04},'<')
  .to('.loading-wrap .split span',{y:'-100%',duration:.5,stagger:.04},'+=1')
  .to('.reveal-2',{y:'-100%'},'-=.5')
  .from('.mv__body h1 span',{y:'100%',duration:.5,stagger:.01},'<')
  .from('.mv__body h2 span',{y:'100%',duration:.5,stagger:.01},'<')
  .from('.mv__body p span',{y:'100%',duration:.5},'>')


  //動画レスポンシブ対応
  var elemList = document.getElementsByClassName("routingByBreakpoint");

	for(var i = 0, l = elemList.length; i < l; i++){
		var sourceList = elemList[i].getElementsByTagName("source");

		routingByBreakpoint(sourceList);
	}

});