Blog/JavaScript

[ScrollMagic] 스크롤매직 라이브러리 - 중급편

나나 (nykim) 2019. 8. 27. 11:32
320x100

기초편에 이어 중급편입니다.

공식 예제 중 ADVANCED에 해당하는 내용을 살펴보겠습니다 :-9

히어뤼고!

 


 

1. 섹션 와이프 (매뉴얼)

 

기초편에서는 단순히 아래에서 위로 올라와 고정되는 와이프였다면,

이번에는 상하좌우에서 슝 날아와 고정되는(?) 섹션 와이프를 구현해봅니다.

 

구현원리는 간단합니다.

너비높이 100%의 풀페이지 컨테이너를 만든 다음, 얘를 setPin으로 고정시킵니다.

그리고 그 안에 들어갈 여러 개의 섹션을 만들고 absolute 시킵니다.

그 다음에는 섹션의 위치를 -100%로 두었다가, 스크롤 되면 0% 위치로 움직이게 합니다.

여기에 GSAP을 쓰면 짱 편하니까 그렇게 작성합시다ㅋㅋㅋㅋㅋ

 

우선 마크업을 합니다.

<div id="container">
	<section class="panel one">
		<b>ONE</b>
	</section>
	<section class="panel two">
		<b>TWO</b>
	</section>
	<section class="panel three">
		<b>THREE</b>
	</section>
	<section class="panel four">
		<b>FOUR</b>
	</section>
</div>

 

CSS도 작성한 다음...

 

#container {
	width: 100%;
	height: 100%;
	overflow: hidden;
}

.panel {
	position: absolute;
	top: 0px;
	left: 0px;
	width: 100%;
	height: 100%;
	font-size: 60px;
	text-align: center;
	color: #fff;
}

 

JS를 작성합니다.

 

var controller = new ScrollMagic.Controller();
var wipeAnimation = new TimelineMax()
.fromTo(".two", 1, {x:"-100%"}, {x:"0%"} )
.fromTo(".three", 1, {y:"-100%"}, {y:"0%"} )
.fromTo(".four", 1, {x:"100%"}, {x:"0%"} )

var scene = new ScrollMagic.Scene({
      triggerElement: "#container",
      triggerHook: "onLeave",
      duration: "500%" //이 값이 클 수록 천천히 덮어씀
})
.setPin("#container")
.setTween(wipeAnimation)
.addIndicators() 
.addTo(controller);

 

Timeline을 통해서, 각 섹션이 -100%에서 0%로 이동하는 걸 볼 수 있습니다.

 

여기서 체크할 점은, scene에 주어진 duration 값이 크면 클수록 스크롤을 더 많이 해야한다는 것입니다.

달리 말하면 다음 섹션이 더 천천히 스와이프 된다고 할 수도 있죠.

 

See the Pen ScrollMagic Demo (8) - Dynamic Section Wipe by NY KIM (@nykim_) on CodePen.

 

 

 

 

 

 

 

 

 


 

2. 섹션 슬라이드

 

 

이 다음은 섹션 슬라이드입니다. 위의 예제와 비슷하긴 하지만 좀 더 다이내-믹!한 효과를 줘보겠습니다.

원리는 동일합니다. container를 고정시키고, 섹션이 움직이도록 애니메이션을 설정하면 됩니다.

 

먼저 마크업입니다.

<div id="pinContainer">
  <div id="slideContainer">
    <section class="panel one">
      <b>ONE</b>
    </section>
    <section class="panel two">
      <b>TWO</b>
    </section>
    <section class="panel three">
      <b>THREE</b>
    </section>
    <section class="panel four">
      <b>FOUR</b>
    </section>
  </div>
</div>

 

아까와는 다르게 컨테이너가 두 개인 구조입니다.

pinContainer는 고정하고, slideContainer의 위치만 움직일 거에요.

 

#pinContainer {
	width: 100%;
	height: 100%;
	overflow: hidden;
	-webkit-perspective: 1000;
	perspective: 1000;
}

#slideContainer {
	width: 400%;// 100*4 slides
	height: 100%;
}

.panel {
	float: left;
	width: 25%; // 400/25 = 100%
	height: 100%;
	font-size: 60px;
	text-align: center;
	color: #fff;
}

 

따라서 slideContainer는 100%*4개 섹션 = 400%만큼의 너비를 주고,

각 섹션은 그 25%의 너비를 갖도록 합니다.

 

그리고 자바스크립트를 작성합니다.

 

var controller = new ScrollMagic.Controller();
var wipeAnimation = new TimelineMax()
  // animate to second
  .to("#slideContainer", 1, { z: -180 })
  .to("#slideContainer", 1, { x: "-25%" })
  .to("#slideContainer", 1, { z: 0 })
  // animate to third
  .to("#slideContainer", 1, { z: -180, delay: 0.6 })
  .to("#slideContainer", 1, { x: "-50%" })
  .to("#slideContainer", 1, { z: 0 })
  // animate to forth
  .to("#slideContainer", 1, { z: -180, delay: 0.6 })
  .to("#slideContainer", 1, { x: "-75%" })
  .to("#slideContainer", 1, { z: 0 })

var scene = new ScrollMagic.Scene({
  triggerElement: "#pinContainer",
  triggerHook: "onLeave",
  duration: "600%" //이 값이 클 수록 천천히 덮어씀
})
  .setPin("#pinContainer")
  .setTween(wipeAnimation)
  .addIndicators()
  .addTo(controller);

 

#pinContainer에게 perspective를 주었으니 z값을 이용해 slideContainer에게 3D 입체 효과를 줄 수 있습니다.

마찬가지로 scene의 duration 값이 클 수록 더 많은 스크롤이 필요합니다.

 

 

See the Pen ScrollMagic Demo (9) - Dynamic Section Slide by NY KIM (@nykim_) on CodePen.

 

 

 

 

 

 

 

 


 

 

3. SVG 라인 드로잉

 

스크롤을 하면 SVG 라인이 그려지는 매직!

을 지금부터 만들어봅시다 XD

 

우선 SVG 라인 애니메이션에 대해 간단히 짚고 넘어가겠습니다.

이때 SVG는 당연하게도 stroke속성을 갖고 있어야 하는데, 우리는 이 stroke를 움직이게 만들 거니까요!

 

stroke-dassharray 라는 CSS 속성이 있습니다. 이 속성을 적용시키면, 선이 대쉬 형태가 되며 값만큼 간격을 갖게 됩니다.

예를 들어 path의 길이가 100이고, dasharray 값이 50이라면 path는 절반만 보입니다.

만약 'dasharray 값 = path 길이'라면 path는 온전히 보이게 됩니다. path의 길이만큼 간격을 갖게 되니까요.

 

한편 이때! stroke-dashoffset 이란 속성을 줘봅니다. 이는 dasharray의 시작 위치를 설정합니다.

그럼 'dasharray 값 = path 길이'일 때, 'dashoffset 값 = path 길이'라면 어떨까요? 그럼 path는 보이지 않게 됩니다 (두둥)

 

그래서 결국 라인 드로잉 애니메이션을 보여주려면,

'dashoffset 값 = dasharray 값 = path 길이'으로 설정한 다음, dashoffset의 값을 점점 0으로 줄여가면 됩니다.

 

path의 길이는 getTotalLength() 메서드를 통해 구할 수 있습니다.

 

 

그럼 직접 만들어보며 감을 익혀보죠!

우선 아무 SVG나 준비합니다. 당연히 <path d="..."/> 형태여야 합니다!

 

그리고 path의 길이를 구해 style로 지정하는 함수를 작성합니다.

 

var st = document.querySelector(".st1");

function pathPrepare(el) {
  var lineLength = el.getTotalLength();
  el.style.strokeDasharray = lineLength;
  el.style.strokeDashoffset = lineLength;
}

pathPrepare(st);

 

아까 말했듯, strokeDasharray와 strokeDashoffset을 path길이와 동일하게 맞춰주었습니다.

 

그런 다음 라이브러리를 사용하여,

strokeDashoffset을 0으로 만듭니다.

 

var controller = new ScrollMagic.Controller();
var tween = new TimelineMax()
  .add(TweenMax.to(st, 0.9, {
    strokeDashoffset: 0,
    ease: Linear.easeNone
  }))
  .add(TweenMax.to(st, 1, {
    stroke: "#ffffff",
    ease: Linear.easeNone
  }), 0);

var scene = new ScrollMagic.Scene({
    triggerElement: "#trigger1",
    duration: 200,
    tweenChanges: true
  })
  .setTween(tween)
  .addIndicators({
    colorStart: "#ffffff",
    colorEnd: "#000000"
  })
  .addTo(controller);

 

 

See the Pen ScrollMagic Demo (10) - SVG line animation by NY KIM (@nykim_) on CodePen.

 

 

 

 

 

 

 


 

4. 컨테이너 스크롤

 

body에서 스크롤하는 게 아니라, 커스텀 컨테이너 내부에 스크롤 애니메이션을 작성할 수도 있습니다.

Controller 옵션으로 {container: "컨테이너명"}을 지정하면 됩니다.

 

 var controller = new ScrollMagic.Controller({
   container: "#container"
 });
 
 //....

 

See the Pen ScrollMagic Demo (11) - Container by NY KIM (@nykim_) on CodePen.

 

 

 

 

 

 

 


 

5. 앵커 링크 스크롤링

 

앵커 클릭 시 해당 지점으로 스크롤시킬 때는 GSAP의 scrollToPlugin을 이용할 수 있습니다.

플러그인으므로 추가로 가져다 써야합니다.

 

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/plugins/ScrollToPlugin.min.js"></script>

 

그리고 컨트롤러의 scrollTo를 TweenMax로 정의해줍니다.

scrollTo() 메서드에 대한 내용은 공식 문서를 참고하세요.

 

controller.scrollTo(function (newpos) {
	TweenMax.to(window, 0.5, {scrollTo: {y: newpos}});
});

 

그런 다음 앵커를 눌렀을 때 해당 위치로 이동하게끔 처리합니다.

원한다면 pushState()를 통해 브라우저 히스토리에 추가할 수도 있습니다.

 

var menu = document.querySelector("#menu");
menu.addEventListener("click", function (e) {
	var id = e.target.hash;
	e.preventDefault();
	controller.scrollTo(id);
	if (window.history && window.history.pushState) {
	  history.pushState("", document.title, id);
	}
});

 

 

See the Pen ScrollMagic Demo (12) - Anchor by NY KIM (@nykim_) on CodePen.

 

 

 

 

 

 


 

6. 패럴렉스 스크롤

 

이번에는 스크롤 애니메이션에서 자주 쓰이는 패럴렉스를 배워봅니다 ;-9

배경화면이 교차되어 입체적으로 보이게 하는 방법인데,

background-position 값을 저마다 다르게 주면 됩니다.

 

여기 총 네 개의 배경 레이어가 있습니다.

 

  <div id="backContainer">
    <div class="back back1"></div>
    <div class="back back2"></div>
    <div class="back back3"></div>
    <div class="back back4"></div>
  </div>

 

그런 다음 absolute 시켜놨죠.

 

#backContainer {
  overflow-x: hidden;
  overflow-y: hidden;
  width: 100%;
  height: 101vh;
}

.back {
  position: absolute;
  width: 300%;
  height: 100%;
  background-repeat: repeat-x;
}

 

마지막으로 타임라인을 생성하고, 백그라운드 포지션 값을 바꿔줍니다.

이때 duration으로 스크롤 길이를 조절하고, setPin으로 화면에 고정시킬 수 있습니다.

 

(function () {

  var controller = new ScrollMagic.Controller();
  var tween = new TimelineMax()
    .add([
      TweenMax.to("#backContainer .back1", 1, {
        backgroundPosition: "-200%",
        ease: Linear.easeNone
      }),
      TweenMax.to("#backContainer .back2", 1, {
        backgroundPosition: "-150% 0",
        ease: Linear.easeNone
      }),
      TweenMax.to("#backContainer .back3", 1, {
        backgroundPosition: "-50% 0",
        ease: Linear.easeNone
      }),
      TweenMax.to("#backContainer .back4", 1, {
        backgroundPosition: "-100% 0",
        ease: Linear.easeNone
      })
    ]);
  var scene1 = new ScrollMagic.Scene({
      duration: "1000%"
    })
    .setTween(tween)
    .setPin("#backContainer")
    .addIndicators();


  controller.addScene(scene1);

}())

 

(이미지 출처는 요기요!)

 


 

7. 패럴렉스 섹션

 

이번 패럴렉스는 이미지가 아니라 섹션에 적용해보겠습니다.

이 효과를 적용하려면 부모 컨테이너가 필요합니다.

<div id="parallax1" class="parallaxParent">
  <div class="background bg1">
    <strong class="title">Parallax</strong>
  </div>
</div>

 

그리고 부모 컨테이너의 높이는 뷰포트 전체로 정합니다.

자식 요소의 높이는 200%로 설정하되, top:-100% 값을 줘서 중앙이 보이게 합니다.

 

.parallaxParent {
	height: 100vh;
	overflow: hidden;
}

.background {
	height: 200%;
	position: relative;
	top: -100%;
}

 

대략적인 구조를 그림으로 표현하면 이런 느낌이에요! 👇

 

 

이 상태에서 우리가 해줄 건, 스크롤해서 parallaxParent에 닿으면

그 자식인 background가 아래로 이동하게끔 합니다.

그럼 height가 200%여서 가려져있던 background의 윗부분이 보이겠죠?

여기에 duration을 지정해줘서 스크롤에 따라 이동하게 하면, 우리가 원하는 패럴렉스 효과를 줄 수 있습니다.

 

대략 이런 느낌적인 느낌

 

위 내용을 코드로 바꾸면 이렇게 됩니다.

 

(function () {

  var controller = new ScrollMagic.Controller({
		globalSceneOptions: {triggerHook: "onEnter"}
	});
	
	new ScrollMagic
		.Scene({triggerElement: "#parallax1", duration: "200%"})
		.setTween("#parallax1 > div", {y: "40%", ease: Linear.easeNone})
		.addIndicators()
		.addTo(controller);
	
	new ScrollMagic
		.Scene({triggerElement: "#parallax2", duration: "175%"})
		.setTween("#parallax2 > div", {y: "30%", ease: Linear.easeNone})
		.addIndicators()
		.addTo(controller);

}())

 

 

See the Pen ScrollMagic Demo (13) - Parallax Sections by NY KIM (@nykim_) on CodePen.

 

 


 

이렇게 중급 편도 무사히 마쳤습니다! 🥰

728x90