Front/Library

Apple 제품 페이지 스크롤 애니메이션

oodada 2020. 11. 18. 10:04

Apple은 제품 페이지의 세련된 애니메이션으로 유명합니다. 예를 들어, 페이지를 아래로 스크롤하면 제품이보기에 들어가고, MacBook은 접 히고 iPhone은 회전하면서 하드웨어를 과시하고 소프트웨어를 시연하며 제품 사용 방식에 대한 대화식 이야기를 들려줍니다.

iPad Pro의 모바일 웹 경험 비디오를 확인하십시오.

 

 

출처 : Twitter

당신이 보는 많은 효과는 HTML과 CSS에서만 만들어지지 않습니다. 그러면 무엇을 물어? 글쎄, 이해하기가 조금 어려울 수 있습니다. 브라우저의 DevTools를 사용하더라도 요소를 지나칠 수없는 경우가 많기 때문에 항상 답을 알 수있는 것은 아닙니다 <canvas>.

이러한 효과 중 하나를 자세히 살펴보고 어떻게 만들어 졌는지 확인하여 자체 프로젝트에서 이러한 마법 효과 중 일부를 재현 할 수 있습니다. 구체적으로 AirPods Pro 제품 페이지 와 영웅 이미지에서 빛이 이동하는 효과를 복제 해 보겠습니다 .

 

 

기본 개념

아이디어는 연속적인 이미지 시퀀스와 같은 애니메이션을 만드는 것입니다. 플립 북처럼! 복잡한 WebGL 장면이나 고급 JavaScript 라이브러리가 필요하지 않습니다.

각 프레임을 사용자의 스크롤 위치에 동기화하면 사용자가 페이지를 아래로 스크롤하거나 위로 스크롤 할 때 애니메이션을 재생할 수 있습니다.

 

마크 업과 스타일로 시작

이 효과를위한 HTML과 CSS는 <canvas>우리가 JavaScript로 제어 하는 요소 내에서 ID를 부여함으로써 마술이 일어나기 때문에 매우 쉽습니다 .

CSS에서 문서 높이를 100vh <body>로 설정하고이 작업을 수행하는 데 필요한 스크롤 길이를 제공하기 위해 그보다 5⨉ 더 크게 만듭니다. 또한 문서의 배경색을 이미지의 배경색과 일치시킵니다.

우리가 할 마지막은 위치입니다 <canvas>, 중심이, 그리고 제한 max-width과 height는 뷰포트의 크기를 초과하지 않도록.

html {
  height: 100vh;
}


body {
  background: #000;
  height: 500vh;
}


canvas {
  position: fixed;
  left: 50%;
  top: 50%;
  max-height: 100vh;
  max-width: 100vw;
  transform: translate(-50%, -50%);
}

 

지금은 페이지를 아래로 스크롤 할 수 있으며 (콘텐츠가 뷰포트 높이를 초과하지 않더라도) 뷰포트 <canvas>의 맨 위에 머물러 있습니다. 이것이 우리에게 필요한 모든 HTML과 CSS입니다.

이미지로드로 이동하겠습니다.

올바른 이미지 가져 오기

이미지 시퀀스로 작업 할 것이므로 (다시 한 번 플립 북처럼) 파일 이름이 오름차순 (예 : 0001.jpg, 0002.jpg, 0003.jpg 등)에서 순차적으로 번호가 매겨진다고 가정합니다. 동일한 디렉토리.

사용자의 스크롤 위치에 따라 원하는 이미지 파일의 번호로 파일 경로를 반환하는 함수를 작성합니다.

const currentFrame = index => (
  `https://www.apple.com/105/media/us/airpods-pro/2019/1299e2f5_9206_4470_b28e_08307a42f19b/anim/sequence/large/01-hero-lightpass/${index.toString().padStart(4, '0')}.jpg`
)

이미지 번호는 정수이므로 문자열로 변환하고 padStart(4, '0')파일 이름과 일치하는 4 자리 숫자에 도달 할 때까지 색인 앞에 0을 추가 하는  사용해야 합니다. 예를 들어이 함수에 1을 전달하면 0001이 반환됩니다.

이는 이미지 경로를 처리하는 방법을 제공합니다. 다음은 <canvas>요소에 그려진 시퀀스의 첫 번째 이미지입니다 .

See the Pen Apple AirPods Pro Animation (static image) by Jurn (@j-v-w) on CodePen.

 

보시다시피 첫 번째 이미지가 페이지에 있습니다. 이 시점에서 그것은 단지 정적 파일 일뿐입니다. 우리가 원하는 것은 사용자의 스크롤 위치에 따라 업데이트하는 것입니다. 그리고 우리는 단순히 하나의 이미지 파일을로드 한 다음 다른 이미지 파일을로드하여 교체하는 것을 원하지 않습니다.  <canvas>이미지를 그리고 시퀀스의 다음 이미지로 드로잉을 업데이트 하려고합니다 (하지만 잠시 후에 다룰 것입니다).

우리는 이미 전달한 번호를 기반으로 이미지 파일 경로를 생성하는 함수를 만들었으므로 이제해야 할 일은 사용자의 스크롤 위치를 추적하고 해당 스크롤 위치에 해당하는 이미지 프레임을 결정하는 것입니다.

사용자의 스크롤 진행 상황에 이미지 연결

시퀀스에서 전달해야하는 숫자 (및로드 할 이미지)를 알기 위해 사용자의 스크롤 진행률을 계산해야합니다. 이를 추적하는 이벤트 리스너를 만들고로드 할 이미지를 계산하기 위해 몇 가지 수학을 처리합니다.

우리는 다음을 알아야합니다.

  • 스크롤이 시작되고 끝나는 곳
  • 사용자의 스크롤 진행률 (예 : 사용자가 페이지 아래로 내려간 정도의 백분율)
  • 사용자의 스크롤 진행에 해당하는 이미지

scrollTop요소의 세로 스크롤 위치를 가져 오는 데 사용할 것 입니다.이 경우 문서의 맨 위에 있습니다. 이것이 시작점 값이됩니다. 문서 스크롤 높이에서 창 높이를 빼서 끝 (또는 최대) 값을 얻습니다. 여기에서 scrollTop 값을 사용자가 아래로 스크롤 할 수있는 최대 값으로 나누면 사용자의 스크롤 진행률을 알 수 있습니다.

그런 다음 해당 위치에 대한 올바른 이미지를 반환하기 위해 스크롤 진행률을 이미지 번호 지정 시퀀스에 해당하는 인덱스 번호로 전환해야합니다. 진행률에 프레임 (이미지) 수를 곱하면됩니다. 우리는 사용합니다 Math.floor() 수 아래로하여 그것을 감싸는 것을 라운드 Math.min()는 결코 프레임의 총 수를 초과하지 않도록 우리의 최대 프레임 수와 함께.

window.addEventListener('scroll', () => { const scrollTop = html.scrollTop; const maxScrollTop = html.scrollHeight - window.innerHeight; const scrollFraction = scrollTop / maxScrollTop; const frameIndex = Math.min( frameCount - 1, Math.floor(scrollFraction * frameCount) ); });

올바른 이미지로 <canvas> 업데이트

이제 사용자의 스크롤 진행률이 변경됨에 따라 어떤 이미지를 그려야하는지 알게되었습니다. <캔버스>의 마법이 등장하는 곳입니다. 게임 및 애니메이션에서 디자인 모형 생성기 및 그 사이의 모든 것을 <canvas>구축 할 수있는 많은 멋진 기능이 있습니다 !

이러한 기능 중 하나는 requestAnimationFrame브라우저 <canvas>와 함께 작동하여 직접 이미지 파일로 작업하는 경우에는 할 수없는 방식 으로 업데이트 하는 메서드 입니다. 그렇기 때문에 요소 또는 배경 이미지 <canvas>대신 접근 방식을 사용했습니다 .<img><div>

requestAnimationFrame브라우저 새로 고침 빈도와 일치하고 WebGL을 사용하여 장치의 비디오 카드 또는 통합 그래픽을 사용하여 렌더링함으로써 하드웨어 가속을 활성화합니다. 즉, 프레임간에 매우 부드러운 전환을 얻을 수 있습니다. 이미지 플래시가 없습니다!

사용자가 페이지를 위아래로 스크롤 할 때 이미지를 교체하기 위해 scroll 이벤트 리스너에서이 함수를 호출 해 보겠습니다. requestAnimationFrame콜백 인수를 취하므로 이미지 소스를 업데이트하고에 새 이미지를 그리는 함수를 전달합니다 <canvas>.

requestAnimationFrame(() => updateImage(frameIndex + 1))

우리는을 해주있어 frameIndex0001.jpg의 이미지 시퀀스가 시작하면서, 우리의 스크롤 진행 계산이 두 값은 항상 정렬되었는지 0이 보장하지만 시작 실제로 시작하기 때문에 1.

이미지를 업데이트하기 위해 전달하는 콜백 함수는 다음과 같습니다.

const updateImage = index => { img.src = currentFrame(index); context.drawImage(img, 0, 0); }

frameIndex함수 에을 전달합니다 . 그러면 <canvas>요소에 그려지는 시퀀스의 다음 이미지로 이미지 소스가 설정 됩니다.

이미지 사전로드로 더욱 향상

기술적으로이 시점에서 완료되었습니다. 하지만 어서, 우리는 더 잘할 수 있습니다! 예를 들어 빠르게 스크롤하면 이미지 프레임 사이에 약간의 지연이 발생합니다. 모든 새 이미지가 새 네트워크 요청을 보내므로 새 다운로드가 필요하기 때문입니다.

새로운 네트워크 요청 이미지를 미리로드해야합니다. 이렇게하면 각 프레임이 이미 다운로드되어 전환이 훨씬 빨라지고 애니메이션이 훨씬 더 부드러워집니다!

우리가해야 할 일은 전체 이미지 시퀀스를 반복하고로드하는 것입니다.

const frameCount = 148;const preloadImages = () => { for (let i = 1; i < frameCount; i++) { const img = new Image(); img.src = currentFrame(i); } };preloadImages();

데모!

 

성능에 대한 빠른 참고

이 효과는 매우 매끄럽지 만 이미지  많습니다. 정확히 148입니다.

이미지를 최적화하거나 CDN이 얼마나 빠른지에 상관없이 수백 개의 이미지를로드하면 항상 페이지가 부풀어 오릅니다. 동일한 페이지에 여러 인스턴스 가 있다고 가정 해 보겠습니다 . 다음과 같은 성능 통계를 얻을 수 있습니다.

데이터 제한이없는 고속 인터넷 연결에는 괜찮을 수 있지만 이러한 사치가없는 사용자에게는 똑같이 말할 수 없습니다. 파업은 까다로운 균형이지만, 모든 사람의 경험과 우리의 결정이 그들에게 어떤 영향을 미치는지 염두에 두어야합니다.

균형을 맞추기 위해 할 수있는 몇 가지 사항은 다음과 같습니다.

  • 전체 이미지 시퀀스 대신 단일 대체 이미지로드
  • 특정 장치에 더 작은 이미지 파일을 사용하는 시퀀스 만들기
  • 사용자가 시퀀스를 시작하고 중지하는 버튼을 사용하여 시퀀스를 활성화 할 수 있습니다.

Apple은 첫 번째 옵션을 사용합니다. 느린 3G 연결에 연결된 모바일 장치 에서 AirPods Pro 페이지 를로드하면 성능 통계가 훨씬 더 좋아 보이기 시작합니다.

그래, 여전히 무거운 페이지입니다. 그러나 성능을 전혀 고려하지 않고 얻을 수있는 것보다 훨씬 가볍습니다. 이것이 Apple이 한 페이지에 너무 많은 복잡한 시퀀스를 가져올 수있는 방법입니다.

 

 


추가 읽기

이러한 이미지 시퀀스가 ​​생성되는 방식에 관심이 있다면 AirBnB  Lottie 라이브러리 를 시작하는 것이 좋습니다 . 이 문서는 After Effects로 애니메이션을 생성하는 기본 사항을 안내하는 동시에 프로젝트에 애니메이션을 포함하는 쉬운 방법을 제공합니다.

 

css-tricks.com/lets-make-one-of-those-fancy-scrolling-animations-used-on-apple-product-pages/

 

Let's Make One of Those Fancy Scrolling Animations Used on Apple Product Pages | CSS-Tricks

Apple is well-known for the sleek animations on their product pages. For example, as you scroll down the page products may slide into view, MacBooks fold

css-tricks.com

 

'Front > Library' 카테고리의 다른 글

slick  (0) 2020.11.20
10+ Best Javascript Scrolling Animation Plugins  (0) 2020.11.19
GaugeMeter  (0) 2020.10.13
무료 템플릿 사이트  (0) 2020.10.13
css Animate  (0) 2020.09.22
티스토리 친구하기