[Next.js, Tailwindcss] 스플래툰3 홈페이지 클론코딩

소고기는레어·2022년 10월 28일
4

Project 🗂

목록 보기
4/15
post-thumbnail

원본 페이지
클론 페이지

2023.05.05 업데이트
트위터 임베드가 때때로 완전히 로드되지 않는 이슈 해결

tailwindcss를 처음 접하고 익숙해질 시간을 갖기 위한 프로젝트로 닌텐도의 스플래툰3 홈페이지를 만들어 보았다.

물방울 애니메이션

트레일러의 재생 버튼과 상단 메뉴의 물방울 애니메이션은 <svg><animate> 태그로 pathd 값에 변화를 주어 구현하였다.

버튼 애니메이션

버튼 애니메이션은 css clip-path 속성으로 구현하였다.

같은 내용에 색만 다른 두 개의 요소를 겹쳐놓고 마우스오버 시 clip-path 애니메이션을 통해 위의 요소를 지우고 아래의 요소를 보여주는 식으로 진행하였다. 포트폴리오 홈페이지의 첫 화면을 제작할 때 사용했던 방법이어서 왠지 반가웠다.

스크롤 애니메이션

스크롤 애니메이션은 ref와 콜백 함수를 인자로 받아서 해당 ref가 뷰포트 하단에 걸치면 콜백 함수를 실행하는 커스텀 훅을 제작해 구현하였다.

콜백으로는 애니메이션 시작을 제어하는 상태의 값을 true 로 업데이트 하는 함수를 전달하였다.

Intersection Observer API를 사용하도록 업데이트 하였다.

배경 & 캐릭터 이미지

언뜻 보면 하나의 이미지로 이루어진 것 같지만 반응형과 애니메이션을 위해 배경과 캐릭터, 그리고 로고 등이 모두 별개의 이미지로 구성되어 있다.

첫 화면의 배경은 <picture> 태그를 활용하여 뷰포트의 사이즈에 맞게 배경 이미지의 사이즈에 변화를 주었고 다른 캐릭터들과 로고, 버튼도 그에 맞게 위치를 조절하였다.

뉴스 슬라이드

슬라이드 페이지 수

슬라이드는 뷰포트 640px 이상에서는 2개씩, 640px 미만은 1개씩 아이템을 오른쪽으로 넘겨볼 수 있다. 따라서 슬라이드의 전체 페이지 수를 구하기 위해 아래와 같은 방법을 사용하였다.

const pageLength = innerWidth >= 640 ? NewsList.length / 2 : NewsList.length;

슬라이드 아이템이 6개일 경우 뷰포트 640px 이상에서는 3페이지, 640px 미만에서는 6페이지가 된다.

슬라이드 방식

처음엔 슬라이드 컨테이너에 x-스크롤을 추가하고 버튼을 통해 스크롤을 제어하는 방식을 사용했지만 스크롤 애니메이션을 구체적으로 커스텀할 수 없다는 점, 그리고 모바일 환경에서의 버벅임 때문에 스크롤 대신 컨테이너의 x 포지션을 직접 조절하는 방식을 채택하였다.

또한 버튼 연타 시 애니메이션의 중첩되어 엉뚱한 곳에서 애니메이션이 멈추는 현상을 방지하기 위해 버튼으로는 페이지의 수만 가감하도록 하였고, 페이지가 변하면 (페이지당 너비 * 현재 페이지) 로 컨테이너의 x 포지션을 구하고 이동시키는 방법을 사용하였다.

페이지당 너비는 컨테이너와 아이템의 여백, 크기 등을 모두 반영하여 구해지는 값이기 때문에 리사이즈 시 값이 변한다. 따라서 뷰포트 크기가 변하면 값을 모두 새로 구하도록 하였고 이벤트 리스너에 debounce를 적용해 불필요한 값 재설정을 방지하였다.

슬라이드의 애니메이션은 gsap, 버튼의 애니메이션은 css로 구현하였다.

트위터

트위터 위젯의 구현은 임베디드 방식을 사용하였다.

처음에는 트위터 api로 트윗 데이터를 긁어온 다음 직접 스타일을 적용하여 트위터처럼 꾸미는 방식을 사용한 줄 알았으나 트위터 api에 대해 공부하던 도중 임베디드 트위터의 존재를 알게 되었다.

임베디드 트위터는 개별 트윗 혹은 프로필, 해시태그와 목록 등 다양한 범주에서 원하는 내용을 바로 웹사이트에 불러올 수 있으며, 간단한 레이아웃이나 사이즈 등도 조절이 가능해 여러모로 활용도가 높은 기능으로 보인다.

푸터 애니메이션

푸터의 인터렉티브 애니메이션은 Matter.js와 D3.js로 구현하였다.

뷰포트 사이즈 640px 이하의 환경에서는 애니메이션을 빼고 고정된 이미지를 출력하도록 하였다.

Matter.js

Matter.js는 2D 물리엔진을 구현할 수 있게 해주는 라이브러리이다.

물리 효과가 적용된 체인 만들기

직사각형을 여러개 생성 후 길게 이어 체인으로 연결하고, 양 끝의 직사각형을 캔버스 양 끝(보다 더 바깥)에 고정하여 뷰포트를 가로지르는 체인을 생성하였다.

직사각형의 개수가 많을 수록 더 유연한 체인의 움직임을 표현할 수 있는데, (innerWidth / 15) 개의 직사각형을 생성하도록 하여 화면에 맞는 직사각형 개수를 유지할 수 있도록 하였다.

마우스에 반응하는 체인

기본 상태에서는 드래그를 통해 체인을 움직일 수 있지만, 별도의 클릭 없이 마우스의 움직임만으로 체인에 충돌 효과를 부여할 수 있어야 했다.

먼저 체인과 충돌 가능한 원을 생성한 뒤, 원이 마우스 포인터의 위치를 따라가도록 만들었다.

원을 투명하게 만들면 마우스가 체인과 충돌하는 것처럼 보일 수 있다.

체인의 부자연스러운 움직임을 방지하기 위해 마우스가 캔버스의 중앙에서 어느정도 벗어날 경우 원과 체인의 충돌을 비활성화하였다.

D3.js

D3.js는 데이터를 시각화하고 다양한 차트를 만드는 라이브러리이다.
요상하게 생긴 Matter.js의 체인 대신 예쁘게 다듬어진 모습으로 물결을 표현하기 위해 사용하였다.

체인을 따라 움직이는 SVG

체인을 구성하는 직사각형들의 위치를 저장하는 상태를 하나 만들고, requestAnimationFrame() 함수로 매 프레임마다 상태를 업데이트하도록 하였다.

저장한 직사각형들의 위치는 D3로 가공하여 path로 만들고 이 path를 SVG에 전달하여 검은 물결을 표현하였다.

마지막으로 Matter.js의 캔버스는 투명하게 만들고 Matter.js의 체인을 따라 움직이는 SVG만 남겨두어 마우스의 움직임에 반응하는 파도를 완성하였다.

원본은 보다 더 실제 물결 같은 파동을 보여주는데, 그래도 나름 비슷하게 만들어보고자 노력했다.




평소 진행해 온 프로젝트들이 너무 동적 웹 애플리케이션에 치우쳐 있어서 정적 웹 페이지도 오랜만에 만들어 보기 위해 선택한 웹사이트인데, 원본 페이지가 반응형으로 잘 짜여있어서 tailwindcss를 활용하고 복습하기 좋았다. 재밌는 애니메이션 효과도 여럿 포함되어 있어서 처음엔 어떻게 만들지 고민을 좀 했지만 결과적으로는 재밌었고 배울게 많은 프로젝트였다.

profile
https://www.rarebeef.co.kr/

0개의 댓글