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

    2019. 8. 27.

    by. 나나 (nykim)

    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

    댓글 4

    • 프로필사진
      joonsol 2020.02.13 15:27

      질문있습니다. section wipes에서 고정메뉴로 링크를 걸고자 하는데요
      http://sixtat.dothome.co.kr/scroll/
      여기 보시면 아시겠지만, section link가 일부만 발생하는데요 이 문제를 해결하고자 하면 어떻게 하면 될까요?
      카톡계정 loo4love@nate.com입니다. 연락부탁드려요~ 감사합니다. 아니면 댓글 보러 올께요!

      • 프로필사진
        나나 (nykim) 2020.07.01 17:14 신고

        아이고ㅠㅠ 제가 이걸 너무 늦게 봤네요...
        앵커 스크롤은 플러그인을 쓰는 게 편하실 것 같습니다.
        GSAP에서 scrollToPlugin을 제공하고 있습니다.

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

    • 프로필사진
      초보퍼블리셔 2020.09.05 00:17

      안녕하세요! 너무나 도움되는 글 감사합니다 ㅠㅠ 초짜라서 아직 실력이 부족한데 혹시 http://everylastdrop.co.uk/ 이 사이트 처럼 뭔가 이미지들이 합체되고 분산되보이는 식의 효과(정확히는 기계 부품이 합체되는 형태를 패럴렉스 스크롤로 만들어야 합니다 ㅠㅠ) 줄려면 어떤 방법을 이용하면 좋을까요? 하드 코딩 실력이 부족하여 플러그인 찾다가 skrollr 보았는데 이 아이는 반응형이 힘들다구 해서요..ㅠ 조언 주시면 감사하겠습니다!

    • 프로필사진
      감동 2021.05.11 10:11

      이렇게 자세한 설명이 있을 수 있다니 감동받고 갑니다!