ABOUT ME

-

Today
-
Total
-
  • 애플처럼 화려한 Parallax Scroll 랜딩 페이지 개발해보기
    Study/Frontend 2023. 1. 13. 15:15
    반응형

    Parallax scrolling is a web site trend where the background content (i.e. an image) is moved at a different speed than the foreground content while scrolling.


    패럴랙스 스크롤링 기법을 간단히 말하면 스크롤에 따른 애니메이션 효과라고 할 수 있다. 패럴랙스 스크롤링 기법을 적용한 대표적인 웹사이트는 애플 제품 소개 페이지이다. 볼 때마다 감탄사가 나왔었는데, 회사에서 이와 같은 인터랙션 사이트를 구현할 기회가 생겼다!
    "나도 애플처럼 화려한 인터랙션을 넣을 거야😎"라고 속으로 호기롭게 외치며 스터디를 시작했다.

    회사에서 인프런 바우처를 지원해 줬기 때문에 강의 1, 강의 2를 들으며 패럴랙스 스크롤링 원리를 익혔다. 정말 많은 도움이 됐던 강의다.
    패럴랙스 스크롤링 기법의 핵심은 스크롤 높이와 움직일 객체의 포지션을 동적으로 계산하고, css 중 transform 속성에서 translate, scale 등을 이용하는 게 핵심이다. 그리고 transition에서 easing을 조절해서 스크롤에 따른 애니메이션의 가속도를 자연스레 설정하는 것이 중요하다. 그리고 requestAnimationFrame을 활용해서 부드럽게 화면에 그려주는 것이 중요하다.

    하지만 실무에 바로 적용하기에는 스터디 시간이 약간 부족했고, 결국 라이브러리를 활용하기로 했다.
    패럴랙스 스크롤링을 구현하기에 가장 적합한 라이브러리로 GSAP의 Scroll Trigger 라이브러리를 택했고, 빠른 시일 내에 구현할 수 있었다. 스크롤 트리거는 말 그대로 스크롤 기반으로 애니메이션을 구현하는 건데, 트리거 엘리먼트를 지정하고 뷰포트에 트리거 엘리먼트가 등장하면 지정한 엘리먼트의 애니메이션이 작동된다. 사용법도 익히기 쉽고 성능도 좋아서 처음 시도한 것 치고 금방 구현할 수 있었다.

    👇🏻 패럴랙스 스크롤 데모 구경하기👇🏻

    Parallax Scroll Site

    parallax-scroll-site.netlify.app


    GSAP 홈페이지에 가보면 문서가 잘 돼있어서 굳이 사용법은 적지 않아도 될 것 같고, 겪었던 문제점과 해결법을 공유해보려고 한다.

    🔥 GSAP 스크롤 트리거 트러블 슈팅


    어려웠던 점은 회사 측에서 요청했던 패럴랙스 스크롤링은 애플 사이트와는 조금 다르게 정말 한 편의 애니메이션을 제작하는 것과 같았다.
    다양한 scene이 존재했고, 스크롤링하면서 여러 리소스들이 뷰포트 안으로 들어와서 움직여야 했다.

    1. 스크롤 높이는 최대한 넉넉하게 잡기

    스크롤에 따라 리소스가 움직이기 때문에 트리거를 애니메이션에 필요한 총 스크롤 높이의 엘리먼트로 고정해 놓고, 정해진 높이 안에서 움직임을 계산하는 게 편리했다. 그리고 최대한 스크롤 높이는 넉넉하게 잡는 것이 좋다. 처음에 너무 작게 잡았다가 여러 기기로 테스트해 보면서 부족함을 느껴서 다시 재조정하며 굉장한 노가다를 반복했다..

    2. 뷰포트 사이즈 대응하기

    반응형으로 제작하기 위해 뷰포트 사이즈에 맞게 움직이는 속도를 조절해야 해서, resize 이벤트가 일어나거나 뷰포트 사이즈에 따라 스크롤 속도를 유동적으로 계산하도록 했다.

    3. 뷰포트 바깥에 리소스 배치하기

    각 scene마다 뷰포트 안으로 들어오는 리소스의 위치가 제각각이기 때문에 position: fixed 로 뷰포트 바깥에 리소스를 배치한 후 움직이는 게 좋다. 그리고 반응형으로 제작할 경우 scene을 기획할 때 최대한 화면 가운데서 인터랙션 일어나는 것이 보여야 하는 것이 관건이다.

    4. 다양한 스크롤 기기 대응하기

    스크롤 기기(트랙패드, 마우스 휠, 모바일 터치 기기 등)에 따라 속도가 다 다르기 때문에 우선은 기기마다 디폴트 설정값을 기본으로 테스트해 보고 속도를 계산하는 것이 최선인 것 같다. 그리고 스크롤 트리거의 scrub 속성을 활용해서 적절히 속도를 조절할 수도 있다.

    5. 크로스 브라우징 테스트하기

    사파리, 크롬, 파이어폭스, 엣지, 네이버 인앱 브라우저까지 크로스 브라우징 테스트로 잘 돌아가는 것을 확인했는데, 이상하게 유독 ios 기기의 카카오톡 인앱 브라우저에서만 버그가 발생했다. 디버깅을 하고 싶었으나 카카오톡 인앱 브라우저는 디버깅조차 할 수 없어서 정말 애먹었다. 디버깅을 위해 원인을 예측해 보고 수정하고 배포해서 인앱 브라우저에서 열어서 확인하는 동작을 수없이 반복했다. 결국 디버깅엔 실패했고, 구글링을 통해 발견한 블로그 글을 보고 ios 기기의 인앱브라우저에서는 이미지를 대체해서 보여주는 방식으로 해결할 수밖에 없었다. 지금 개인적으로 올린 데모에서는 location.href="x-web-search://?" 코드를 사용하여 사파리 앱 URL Scheme을 활용해 인앱 브라우저에서를 사파리를 열어주는 방법으로 인앱 브라우저에서 탈출시키도록 했다.


    🛠️ 이미지 성능 최적화


    패럴랙스 스크롤링 랜딩 페이지는 원래 예정에 없었다. 그냥 애니메이션 제작하고 그 영상을 랜딩 페이지 최상단에서 플레이하기로 했는데, 계획이 바뀌면서 패럴랙스 스크롤링 기법을 적용해야 했다. 그래서 기존에 아트 팀에서 애니메이션을 위해 모든 아트 작업을 포토샵으로 작업했기 때문에 이미지 파일을 모두 PNG 파일로 변환해야 했다. 만약 벡터 기반 아트였으면 성능 이슈가 크지 않았을 텐데 PNG 포맷이었기 때문에 좀 더 성능에 큰 영향을 미쳤다. 이미지 용량이 큰 게 많이 들어가다 보니까 특히 모바일에서 스크롤하면 버벅거리는 경우가 많았다. 그래서 이미지를 최적화하는데 집중해야 했다.

    1. 이미지 용량 줄이기

    이미지 최적화에서 사진 용량 줄이기를 빼놓을 수 없다. 올바른 이미지 최적화를 위해서는, 사진 퀄리티는 그대로 유지하면서 용량은 최대한 줄여야 한다. 구글은 사진 용량줄이기를 위해 파일크기를 줄이는 도구 중 ImageOptim을 사용할 것을 권장하는데, ImageOptim 은 맥용 무료 도구이며 이를 사용하면 실제로 JPEG 파일은 69 %, PNG 파일은 40 % 의 용량이 감소된다.
    그 결과 이미지 리소스 사이즈를 총 18.5mb에서 13.2mb 까지 줄이는 데 성공했다.

    2. WebP 이미지 포맷 사용하기

    WebP는 무손실 및 손실 압축을 전부 지원하고, JPEG, PNG 및 GIF 이미지 포맷을 대체할 수 있는 웹에 최적화된 포맷이다. 이 글에 따르면 WebP 이미지는 JPEG, PNG 보다 파일 크기가 일반적으로 25~35% 작아서 성능 향상에 중요한 역할을 할 수 있다고 한다. WebP 이미지 포맷은 현재 기준 IE를 제외한 브라우저에서 모두 지원하는 것으로 알려져 있다.
    기존에 사용하던 PNG 파일 중에 크기가 큰 파일을 모두 WebP 포맷으로 변환하고, WebP 파일을 지원하지 않는 경우에는 PNG파일을 사용하고 그 외에는 WebP 파일을 사용했다. 이를 구현하기 위해 다음과 같이 picture 태그와 source태그, img태그를 이용해야한다.

    <picture> 태그는 <img> 태그의 다중 이미지 리소스를 위한 컨테이너를 정의할 때 사용한다. <picture> 태그는 0개 이상의 <source> 태그와 하나의 <img> 태그로 구성된다.
    <source> 태그는 미디어 리소스를 지정한다. 브라우저가 지원하는 형식으로 나열된 첫 번째 소스를 사용하고, <source> 태그에 나열된 형식 또는 <picture> 태그를 브라우저가 지원하지 않으면 <img> 태그에 지정된 이미지를 로드하는 것으로 대체된다. 따라서 <img> 태그는 항상 가장 마지막에 나열해야 하고 보편적으로 지원하는 미디어 형식의 리소스여야 한다.
    예시 코드는 아래와 같다.

    <picture>
      <source type="image/webp" srcset="flower.webp">
      <source type="image/png" srcset="flower.png">
      <img src="flower.png" alt="flower">
    </picture>


    그 결과 이미지 리소스 사이즈를 총 13.2mb에서 3.5mb까지 줄이는 데 성공했다.


    🛠️ CSS 애니메이션 성능 최적화


    이미지 최적화 이후 피시에서 애니메이션 테스트를 마치고 모바일 테스트를 진행하는데, 굉장한 버벅거림 현상을 마주했다.
    그래서 이미지 최적화뿐만 아니라 애니메이션 성능에도 문제가 있다는 것을 알게 됐고, 애니메이션 최적화를 시작했다.
    애니메이션을 최적화하기 위해서는 우선 브라우저에서 렌더링이 어떻게 일어나는지를 먼저 파악해야 했다.

    출처:&nbsp;https://developer.chrome.com/blog/inside-browser-part1/


    크롬 기준으로 브라우저 아키텍처를 살펴보면 브라우저 프로세스, 렌더러 프로세스, 플러그인 프로세스, GPU 프로세스 등으로 구성되어 있다. 이 중에서 렌더러 프로세스가 브라우저 탭 안에서 일어나는 모든 일을 담당하게 된다. 렌더러 프로세스 안에서도 메인 스레드, 컴포지터 스레드, 래스터 스레드로 나뉘는데, 메인 스레드가 대부분의 스크립트 코드를 처리하고, 컴포지터/래스터 스레드는 화면을 부드럽게 렌더링 하는 것을 처리한다.

    출처: https://web.dev/howbrowserswork/


    일반적으로 메인 스레드에서 Recalculate Style, Layout, Paint 과정이 실행되고 CSS 기반 애니메이션을 컴포지터 스레드에서 실행한다. 위에서 언급했듯이 자바스크립트 코드는 메인 스레드에서 실행되기 때문에 자바스크립트로 애니메이션을 구현할 경우 애니메이션의 우선순위가 밀릴 수 있다. 하지만 CSS 기반 애니메이션을 구현한다면 컴포지터 스레드에서 처리되기 때문에 애니메이션 성능을 최적화할 수 있다.
    그리고 부드러운 애니메이션을 위해서는 렌더링 과정 중 Composite Layers에 영향을 주는 속성만 사용하는 것이 적합하다.
    웹 브라우저 렌더링 과정과 그 과정에 해당하는 CSS 속성을 간단히 살펴보면 다음과 같다.

    1. Recalculate Style : 요소에 적용할 스타일을 계산한다.

    2. Layout : 요소의 모양과 위치를 생성한다.

    position display overflow overflow-y
    width height min-width min-height
    padding margin border border-width
    top bottom left right
    font font-family font-size font-weight
    white-space line-height vertical-align float
    clear      


    3. Paint : 생성된 모든 레이아웃에 픽셀을 추가한다.

    color background visibility text-deocration
    background-image background-position background-repeat background-size
    outline outline-color outline-style outline-width
    border-radius border-style box-shadow  


    4. Composite Layers : 레이어(z-index) 순서대로 레이어를 합성하고 화면에 그린다.

    transform opacity


    위 순서에 따르면 Layout 관련 속성을 바꾸면 Paint, Composite Layers 순서를 거치기 때문에 성능 저하가 일어난다. 이를 Reflow라고 한다.
    또한 Paint 관련 속성을 바꾸면 Composite Layers 순서를 거치기 때문에 성능 저하가 일어난다. 이를 Repaint라고 한다.
    따라서 CSS 애니메이션 성능을 최대로 발휘하려면 Composite Layers 관련 속성(transform, opacity)만 바꾸는 것이 가장 좋다.


    패럴랙스 스크롤 랜딩페이지를 만들어보면서 패럴랙스 스크롤링의 원리를 익힘과 동시에 이미지와 애니메이션 최적화에 대해 많이 배울 수 있었다. 다음에 기회가 된다면 라이브러리를 사용하지 않고 순수 CSS, JS로만 패럴랙스 스크롤링을 구현해보고 싶다!



    참고 문헌
    https://developer.chrome.com/blog/inside-browser-part1/
    https://developer.chrome.com/blog/inside-browser-part3/#style-calculation
    https://greensock.com/react/
    https://greensock.com/react-advanced
    https://edidiongasikpo.com/using-gsap-scrolltrigger-plugin-in-react
    https://wit.nts-corp.com/2020/06/05/6134

    반응형

    댓글