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

    2019. 8. 26.

    by. 나나 (nykim)

    전부터 계속 써보고 싶었던 ScrollMagic 라이브러리!!! 를 드디어 공부해봅니다 (꺅)

    참고한 글은 아래와 같습니다.

    - Building Interactive Scrolling Websites with ScrollMagic.js [링크]

     

     

    1. 초기 설정

     

    우선 아묻따 ScrollMagic을 도입해줍니다.

    CDN은 아래와 같습니다.

     

    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/plugins/debug.addIndicators.min.js"></script>

     

    저 debug로 시작되는 파일은 화면에 인디케이터를 표시해주는데, 덕분에 좀 더 수월하게 작업이 가능합니다.

    이 라이브러리는 jQuery도 지원해주는 거 같던데 여기선 그냥 바닐라로 작성하겠습니다ㅎㅎ

     

    그리고 수려한 애니메이션 제작을 도와줄 GSAP도 도입합니다.

     

    <script src="//cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.5/plugins/animation.gsap.js"></script>

     

    GSAP 이외에 Velocity도 지원하고 있지만, 이 글에 따르면 GSAP이 좀 더 크로스브라우징이 잘 되어 있다고 합니다.

    그러니 여기서는 GSAP을 써봅시다! 어... 사실 얘밖에 쓸 줄 모르는 거긴 한데요오오...

     

     


     

    2. ScrollMagic의 동작원리

     

    동작원리라는 제목만 보면 되게 어려울 거 같은데, 간단히 쓰자면 이렇습니다.

     

    [1] ScrollMagic 컨트롤러 생성

    [2] Animation 오브젝트 생성

    [3] Scene 오브젝트 생성

    [4] Animation 오브젝트(2번)를 Scene 오브젝트(3번)에 추가

    [5] Scene Object(3번)를 ScrollMaig 컨트롤러(1번)에 추가

     

    써놓고 보니 복잡한 거 같은데,

    그냥 이런 느낌입니다 👇

     

     


     

     

    3. 간단한 동작 만들어보기

     

    일단 테스트용으로 html, css 파일을 만듭니다.

    마크업과 스타일링은 적당히 해줍니다 :9

     

    See the Pen ScrollMagic Demo (1) by NY KIM (@nykim_) on CodePen.

     

     

     

     

     

     

     

    자, 그럼 위 원리대로 우선은 ScrollMagic Controller를 하나 만들어야겠죠?

    new 키워드를 이용해 새로운 인스턴스를 생성합니다.

     

    var controller = new ScrollMagic.Controller();

     

    두 번째는 Animation Object 생성입니다.

    GSAP을 설치했으니 애니메이션을 손쉽게 작성할 수 있습니다.

     

    var tween1 = TweenMax.to('#animate1', 0.5, {
      backgroundColor: "#333333",
      scale: 2.5,
      rotation: 360,
      x: 130
    });

     

    세 번째 할 일은?

    Scene Object를 생성하는 일이였습니다.

     

    var scene = new new ScrollMagic.Scene();

     

    그 다음은 Animation Object를 Scene Object에 추가해야 합니다.

    setTween() 메서드를 사용하고, 인자로 우리가 작성한 애니메이션을 쏙 넣어줍니다.

     

    var scene = new ScrollMagic.Scene().setTween(tween1);

     

    마지막 할 일은 Scene Object를 ScrollMaig Controller에 추가하는 거였죠.

    addTo() 인자로 우리가 작성했던 컨트롤러를 지정합니다.

     

    var scene = new ScrollMagic.Scene()
    .setTween(tween1)
    .addTo(controller);

     

    그리고 가장 중요한 마무리! 이 scene이 일어날 트리거를 지정해줘야 합니다.

    여기서는 #trigger1이라는 요소에 닿으면 애니메이션이 발생하도록 하겠습니다.

    triggerElement: "#trigger1"과 같이 작성하면 됩니다.

     

    var scene = new ScrollMagic.Scene({
        triggerElement: "#trigger1"
      })
      .setTween(tween1)
      .addTo(controller);

     

    여기까지만 하면 스크롤에 따라 애니메이션이 작동합니다! (오오어어엌)

    하지만 디버깅을 위해 인디케이터를 추가할게요.

    addIndicators()로 추가할 수 있으며, 옵션으로 이름을 지정할 수도 있습니다.

     

    var scene = new ScrollMagic.Scene({
        triggerElement: "#trigger1"
      })
      .setTween(tween1)
      .addTo(controller)
      .addIndicators({
        name: "1"
      });

     

     

    테스트해보면, #trigger1의 윗부분에 닿는 순간 애니메이션이 작동하는 걸 알 수 있습니다.

    (짝짝짝)

     

     

    한편, offset 값을 줘서 실제 트리거보다 빠르게/느리게 애니메이션을 작동시킬 수도 있습니다.

    아래는 offset으로 150 값을 준 모습입니다.

     

    var scene = new ScrollMagic.Scene({
        triggerElement: "#trigger1",
        offset: 150 
      })
      .setTween(tween1)
      .addTo(controller)
      .addIndicators({
        name: "1"
      });

     

     

     

    duration 값을 지정하면 애니메이션이 얼마나 긴 시간동안 재생될지 설정할 수 있습니다.

    이 값이 작을수록 애니메이션은 더 빨리 끝날 거고, 클수록 더 늦게 끝납니다.

     

    아래 이미지는 duration 값을 각각 40, 100으로 지정하고 같은 지점에서 스크롤을 멈춘 모습입니다.

    전자의 경우 애니메이션이 더 많이 재생된 것을 볼 수 있습니다.

     

     

    (좌) duration: 40 / (우) durationL 100

     

    이때 duration을 100%로 지정하면, 뷰포트 높이에 따라 유동적으로 end의 위치가 정해집니다. (공식 문서 링크)

    아무튼 잘 돌아가니 좋네요!!

     

     


     

    4. 애니메이션 반복시키기

     

    TweenMax의 유용한 기능 중 하나는 yoyo인데요, 애니메이션의 반복 재생을 도와줍니다.

    fromTo() 메서드에 repeat: -1 값을 준다면 무한한 애니메이션 재생이 가능합니다.

     

    var tweenYoyo = TweenMax.fromTo("#animate1", 0.6, {
      backgroundColor: "#333333",
      scale: 1,
    }, {
      scale: 2.5,
      backgroundColor: "#dc143c",
      x: 100,
      rotation: 360,
      repeat: -1,
      yoyo: true
    })
    
    var scene = new ScrollMagic.Scene({
        triggerElement: "#trigger1",
        duration: 150
      })
      .setTween(tweenYoyo)
      .addTo(controller)
      .addIndicators({
        name: "1"
      });

     

     

    실행시켜보면 원이 커지면서 색이 바뀌는 애니메이션이 계속 반복되는 걸 볼 수 있습니다.

    다만 스크롤 지점이 트리거 요소보다 위에 있다면 (=즉, #trigger1에 닿지 않았다면) 애니메이션은 멈춰버립니다.

    또한 duration을 지정한 경우, 그 범위를 넘어가도 애니메이션은 중지됩니다.

     

    start와 end 범위를 넘어가면 애니메이션은 뚝! 멈춥니다

     

     

    See the Pen ScrollMagic Demo (2) by NY KIM (@nykim_) on CodePen.

     

     

     

     

     

     

     

     


     

    5. 연속적인 애니메이션 재생

     

    이번에는 staggerFromTo() 메서드를 이용해 연속적인 애니메이션을 만들어보겠습니다.

    staggerFrom 또는 staggerFromTo의 작성 방법은 아래 공식 문서를 통해 확인할 수 있습니다.

    https://greensock.com/docs/TimelineMax/staggerFrom

    https://greensock.com/docs/TimelineMax/staggerFromTo()

     

    var tweenStagger = TweenMax.staggerFromTo('.icon', 0.4,
      {
        scale: 0.85,
      },
      {
        backgroundColor: "#dc143c",
        scale: 1.2,
        rotation: 360
      },
      0.3
    );
    
    var scene = new ScrollMagic.Scene({
        triggerElement: "#trigger1",
        duration: 150
      })
      .setTween(tweenStagger)
      .addTo(controller)
      .addIndicators({
        name: "1"
      });

     

    위 코드에서 '.icon'은 targets이며(배열 또는 CSS 셀렉터로 지정),

    '0.4'는 duration, '{}'는 각각 fromVars와 toVars, 마지막으로 '0.3'은 stagger(각 트윈 사이의 간격)를 지정한 것입니다.

     

    See the Pen ScrollMagic Demo (3) by NY KIM (@nykim_) on CodePen.

     

     

     

     

     


     

    6. 클래스 토글 / 다수 애니메이션 재생

     

    이번에는 클래스 토글하는 법과 다수의 애니메이션을 재생하는 법을 실험해봅시다!

     

    먼저, 클래스를 붙였다 떼었다 하는 작업은 간단합니다.

    TweenMax를 쓴다면 {className: "+={클래스명}"}만 해주면 되고,

    아니면 그냥 .setClassToggle() 메서드를 써주면 되거든요. 그럼 전능하신 매직스크롤님이 다 해주십니다 허허허

     

    여기선 setClassToggle 메서드를 써보겠습니다.

    들어가야하는 첫 번째 인자는 '클래스를 붙일 대상', 두 번째 인자는 '붙일 클래스 이름'입니다.

     

    다수의 애니메이션을 재생하는 것도 간단해요!

    Animation Object를 여러 개 생성하면 됩니다.

     

    //...
    
    var tween1 = TweenMax.to('#animate1', 0.3, {
      color: "#60c5ba",
      scale: 4,
      y: 10,
      rotation: 360
    });
    
    var tween2 = TweenMax.to('#animate2', 0.3, {
      color: "#ffc952",
      scale: 4,
      y: 10,
      rotation: 360
    });
    
    var tween3 = TweenMax.to('#animate3', 0.3, {
      color: "#6a60a9",
      scale: 4,
      y: 10,
      rotation: 360
    });
    
    //...

     

     

    그리고 Scene Object도 여러 개 작성한 다음 각각 이어주면 됩니다.

     

    (function () {
    
      var controller = new ScrollMagic.Controller({
        globalSceneOptions: {
          duration: 436
        }
      });
    
      var tween1 = TweenMax.to('#animate1', 0.3, {
        color: "#60c5ba",
        scale: 4,
        y: 10,
        rotation: 360
      });
    
      var tween2 = TweenMax.to('#animate2', 0.3, {
        color: "#ffc952",
        scale: 4,
        y: 10,
        rotation: 360
      });
    
      var tween3 = TweenMax.to('#animate3', 0.3, {
        color: "#6a60a9",
        scale: 4,
        y: 10,
        rotation: 360
      });
    
      var scene1 = new ScrollMagic.Scene({
          triggerElement: "#trigger1"
    
        })
        .setClassToggle('.info1', 'active')
        .setTween(tween1)
        .addTo(controller)
        .addIndicators({
          name: "1"
        });
    
    
      var scene2 = new ScrollMagic.Scene({
          triggerElement: "#trigger2"
        })
        .setClassToggle('.info2', 'active')
        .setTween(tween2)
        .addTo(controller)
        .addIndicators({
          name: "2"
        });
    
      var scene3 = new ScrollMagic.Scene({
          triggerElement: "#trigger3"
        })
        .setClassToggle('.info3', 'active')
        .setTween(tween3)
        .addTo(controller)
        .addIndicators({
          name: "3"
        });
    
    }())

     

    See the Pen ScrollMagic Demo (4) by NY KIM (@nykim_) on CodePen.

     

     

     

     

     


     

    7. 요소 고정시키기

     

    스크롤 할 때마다 요소가 따라오게 하려면 어떻게 할까요?

    정답은... setPin() 메서드를 써줍니다!

    특정 지점 이후로는 따라오지 않게 하려면 duration을 지정해주면 됩니다.

     

    //...
    var controller = new ScrollMagic.Controller();
    
    var scene1 = new ScrollMagic.Scene({
      triggerElement: "#trigger1",
      duration: 700,
      offset: 165
    })
    .setPin("#pin1")
    .addIndicators({name: "1 (duration: 700)"}) 
    .addTo(controller);
    //...

    start 지점부터 end 지점까지 요소는 고정됩니다 :>

     


     

    8. CSS를 활용하여 요소 드러내고 숨기기

     

    이번에는 스크롤 이벤트에 아주아주아주 잘 쓰이는, 요소를 드러내고 숨기는 애니메이션입니다.

    그 왜 있잖아요, 스크롤 하면 요소가 페이드인 되는 그런 거 말이죠 ;-9

     

    요소가 trigger에 걸리면 visible 클래스가 붙도록 처리하겠습니다.

    이건 아까 배운 setClassToggle() 메서드를 쓰면 되죠.

    우선 CSS를 작성하고...

     

    .animation1 {
    	color: #fff;
    	padding: 40px;
    	font-size: 50px;
    	background-color: crimson;
    	box-shadow: 3px 14px 30px #ddd;
    	transform: translateY(30px);
    	opacity: 0;
    	
    	&.visible {
    		opacity: 1;
    		transform: translateY(0);
    		transition: all 1.1s;
    	}
    }

     

    scene object를 하나 작성합니다.

     

    var scene = new ScrollMagic.Scene({
      triggerElement: "#trigger1", //트리거 설정
      triggerHook: 0
    })
    .setClassToggle("#animate1", "visible")
    .addTo(controller)
    .addIndicators({
      name: "1"
    });

     

    보면 못보던 옵션이 있네요. 바로 triggerHook입니다.

    이건 viewport에 대해 상대적으로 어느 시점에서 보여줄 건지를 설정합니다.

    0~1 사이의 숫자를 입력하며, 문자열도 가능합니다.

     

    • "onEnter" => 1
    • "onCenter" => 0.5
    • "onLeave" => 0

    디폴트는 onCenter(0.5)이며, 자세한 건 공식 문서를 참고하세요!

     

     

    자, 그럼 백문이 불여일견. 우선은 값을 0으로 지정해봅니다.

    테스트해봤더니... 파란색 인디케이터가 맨 위에 붙어있는 걸 볼 수 있습니다.

    그래서 한참을 내려서 초록색 인디케이터가 뷰포트에서 사라질 때야 setClassToggle이 발생합니다.

     

     

    반면에 값을 1로 해두면 어떨까요? 이건 onEnter죠.

    따라서 초록색 인디케이터가 뷰포트에 들어오는 시점에 setClassToggle이 발생합니다.

    그래서 파란색 인디케이터는 맨 아래에 붙어있습니다.

     

     

    테스트해보니 이 값은 0.8~0.9 사이가 가장 적당한 거 같아요!

    굿굿!!

     

     

    이번에는 연속적으로 주르르륵 나타나는 걸 만들어보겠습니다.

    GSAP의 stagger 기능을 써도 되지만, 여기서는 for문을 사용할게요!

     

    내용은 간단합니다. for문 안에 scene을 넣고, 각 요소가 트리거가 되게끔 합니다.

     

    var revealElements = document.getElementsByClassName("animation2");
    for (var i=0; i<revealElements.length; i++) {
      var scene2 = new ScrollMagic.Scene({
        triggerElement: revealElements[i], //각 요소가 트리거가 됨
        offset: 50,
        triggerHook: 0.9
      })
      .setClassToggle(revealElements[i], "visible") //해당 요소에 클래스 토글
      .addTo(controller)
      .addIndicators({name: "(box) " + (i+1), colorStart:"#F6B352", colorTrigger:"#F6B352"});
    }

     

     

    See the Pen ScrollMagic Demo (6) by NY KIM (@nykim_) on CodePen.

     

     

     

     

     

     


     

    9. 섹션 와이프

     

    다음은 스크롤하면 다음 섹션이 스르륵 올라와 덮는 효과를 만들어보겠습니다.

     

    역시 생각보다 내용은 간단(?!)합니다.

    Trigger Hook이 맨 위에 있다가, 섹션이 Hook에 닿으면(=완전히 스크롤되면) 화면에 고정시켜버리는 거죠.

    이때는 아까 배웠던 setPin()을 사용하면 됩니다.

     

    <div class="wrap">
    	<div class="top">
    		ScrollMagic Demo !!!
    	</div>
    	<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>

     

    먼저 네 개의 섹션을 마크업 한 다음,

    width:100%; height:100%;값을 줘서 화면에 꽉 차게 만들어줍니다.

     

    이후 Controller를 생성하고, 각 section에게 for문을 돌립니다.

     

    var controller = new ScrollMagic.Controller();
    var slides = document.querySelectorAll("section.panel");
    
    for (var i=0; i<slides.length; i++) {
      var scene = new ScrollMagic.Scene()
      .addIndicators() 
      .addTo(controller);
    }

     

    아까 말했듯이, triggerHook은 맨 위에 있어야 합니다.

    Controller에 global option으로 작성합니다.

     

    이때 스트링으로 'onLeave'라 써도 되고, 숫자로 0이라 써도 상관 없습니다 :>

    명확한 계산을 위해 duration은 100%로 지정합니다.

     

    var controller = new ScrollMagic.Controller({
      globalSceneOptions: {
        triggerHook: 'onLeave',
        duration: "100%"
      }
    });
    
    var slides = document.querySelectorAll("section.panel");
    
    for (var i=0; i<slides.length; i++) {
      var scene = new ScrollMagic.Scene()
      .addIndicators() 
      .addTo(controller);
    }

     

    triggerElements는 섹션 각각이 되겠죠.

    그래서 이 섹션의 가장 윗부분이 triggerHook에 닿으면 setPin을 시켜줍니다.

     

    var controller = new ScrollMagic.Controller({
      globalSceneOptions: {
        triggerHook: 'onLeave',
        duration: "100%"
      }
    });
    var slides = document.querySelectorAll("section.panel");
    
    for (var i=0; i<slides.length; i++) {
      var scene = new ScrollMagic.Scene({
        triggerElement: slides[i]
      })
      .setPin(slides[i])
      .addIndicators() 
      .addTo(controller);
    }

     

    자, 이렇게 해놓고 테스트해보면...

    뭔가 이상합니다 (뜨든)

    스크롤을 좀 많이 해야 다음 섹션이 올라오거든요.

     

    왜냐하면 pin되어 있는 동안에는 다음 요소가 밀려나있도록 스크롤매직이 설정해놨기 때문입니다. (공식 문서 링크)

    duration이 지정된 경우 그만큼 요소가 pin되어야 하니까요.

    실제로 콘솔을 열어 확인해보면, spacer가 저절로 생성된 것을 볼 수 있습니다.

     

    누... 누구세요?

     

    따라서 pushFollowers를 false로 지정해놓습니다.

     

    var controller = new ScrollMagic.Controller({
      globalSceneOptions: {
        triggerHook: 'onLeave',
        duration: "100%"
      }
    });
    var slides = document.querySelectorAll("section.panel");
    
    for (var i=0; i<slides.length; i++) {
      var scene = new ScrollMagic.Scene({
        triggerElement: slides[i]
      })
      .setPin(slides[i], {pushFollowers: false})
      .addIndicators() 
      .addTo(controller);
    }

     

    이제 부드럽게 잘 먹히네요!

     

    See the Pen ScrollMagic Demo (7) by NY KIM (@nykim_) on CodePen.

     

     

     


     

    10. 가로 스크롤

     

    가로로 스크롤할 때도 스크롤매직을 사용할 수 있습니다.

    Controller에 {vertical: false} 옵션을 주면 됩니다. 끗.

     

    다만 가로 스크롤이기 때문에, 정말 '가로로' 스크롤 해야지만 볼 수 있습니다.

    세로로 스크롤 했을 때 가로로 보여지는 형태가 아님에 주의!

     

     

    See the Pen ScrollMagic Demo (8) - Horizontal Scroll by NY KIM (@nykim_) on CodePen.

     

     

     

     


     

    스크롤매직 기초편은 여기서 끝~!! :-D

     

    댓글 2

    • 프로필사진
      캐인74 2020.01.30 11:25

      혹시 애니메이션 한번 실행시킬려면 키값을 어떤걸 넣어야되나요?

      • 프로필사진
        나나 (nykim) 2020.02.26 15:29 신고

        앗 답이 많이 늦었습니다ㅠㅠ 댓글이 달린 걸 이제 봤네요!
        애니메이션을 한 번만 실행시키려면 scene객체에 {reverse:false} 값을 주시면 됩니다 :D

        ```
        var scene1 = new ScrollMagic.Scene({
        ㅤㅤtriggerElement: "#trigger",
        ㅤㅤreverse: false //한 번만 실행
        });

        ```