모바일을 위한 새로운 페이지네이션

가로스크롤(제스처)을 이용한 리디자인

홍구
홍구
Feb 26 · 7 min read
Image for post
Image for post

보통 웹 개발할 때 신경쓰지 않고 아무렇게나 만드는게 페이지네이션이다. 대충 굴러다니는 라이브러리 갖다 써도 아무도 뭐라하지 않는다. 그런데 정말 그 웹사이트를 자주 쓰는 사람들에겐, 페이지네이션은 경험에 지속적이고 반복적인 영향을 미치게 된다.

표준도 없고 아무도 개선의 여지는 없어도, 적어도 내가 만드는 웹사이트의 사용자들은 좀 편하게 쓰게하고 싶어서, 기존의 페이지네이션에서 혼돈되는 기호들을 없앤 미니멀한 페이지네이션을 제안한 적이 있었다.

하지만 해당 개선된 방법도 다른것과 마찬가지의 문제는 있다. 내가 현재 1페이지에 있는데, 갑자기 50페이지로 가고 싶을 때 중간 페이지를 여러 번 거쳐서 도달해야한다(각 페이지가 열릴 때 걸리는 딜레이는 덤).

Image for post
Image for post
이 상황에서 대략 50페이지를 선택하고 싶으면, 대여섯 번의 쓸데없는 페이지를 거쳐야 한다

또 모바일에 최적화되어 있지 않은 문제가 있다. 페이지가 몇 천 번대 이상을 넘어가면, 각 페이지 버튼마다 가로폭이 크게 늘어나는데, 이런 경우 모바일의 화면폭을 초과하여 여러줄로 쪼개지는 현상이 필연적으로 발생한다.

Image for post
Image for post
페이지 넘버가 높아지면 폭도 늘어나고 다음줄로 넘어갈 때도 있다

하여 언젠가 모바일과 터치에서도 사용할 수 있는, 기존의 데스크탑에서도 잘 사용할 수 있는 통합된 UI를 만들려고 하고 있었다. 나도 웹개발을 하다보면 페이지네이션 따위는 가장 후순위이기 때문에, 여유가 있을 때 미리 만들어보기로 한다.

스크롤링 페이지네이션

모바일에서는 상하든 좌우든 스크롤은 제스처를 이용하므로 거부감이 없다. 페이지네이션은 현재 페이지가 어디있는지 나타내고, 내가 가고자하는 페이지로 바로 갈 수 있으면 땡이다. 그래서 아래와 같은 방법을 생각해 보았다.

Image for post
Image for post
좌우 스크롤하여 원하는 페이지를 한 번에 갈 수있다

현재 위치를 중심으로 좌우로 갈 수 있는 근처의 페이지들이 표시된다. 가고 싶은 페이지가 화면상에 없다면, 가고 싶은 방향으로 제스처를하여 원하는만큼 이동하면 된다. 원하는 위치로 가서 원하는 페이지를 딱 한 번 선택하면 된다. 멀리있는 페이지로 가기위해 불필요한 중간 페이지 이동이 없는 것이다.

데스크탑에서는 좌우스크롤이 익숙하지 않은 경험이므로, 좌우에 화면 단위로 스크롤을 움직여주는 추가 버튼을 표시해준다(이 버튼은 시각적으로도 방향성을 주게되어 모바일에서도 도움이 된다).

더군다나 화면폭이 얼마가 되었든(심지어 320px에서도), 위 아래로 줄바꿈되거나 깨지지 않는다. 모든 페이지들은 스크롤 영역안에 가두기 때문이다. 시각적으로도 깔끔하다.

Image for post
Image for post
중앙은 스크롤 영역이므로, 모든 화면폭에 따라 넘치지 않는다

최초 코딩

성능이나 스타일이나 기타 등등 생각해 볼 것들이 많지만, 일단 동작을 시키고 정말로 체험해보고 편리한지 테스트를 해보아야 한다.

좌우에 스크롤 버튼 넣고, 가운데 스크롤되는 영역을 두고, 페이지를 1페이지부터 마지막까지 다 때려박는다. 그리고 현재 페이지의 좌표를 계산해서 중앙에 오도록 스크롤해준다. 이렇게 간단할 수가!

Image for post
Image for post

이렇게만해도 작동은 한다. 하지만 문제는.. 총 페이지가 5천개라면? 페이지 버튼을 DOM으로 5천 개만큼 랜더링해야된다. 화면상에 보이든 안 보이든.. 실제로 이렇게 해보니까 초기 랜더링을 위해서 프리징 현상이 나타나고, 스크롤도 버벅인다.

Image for post
Image for post
무식하게 5천개의 DOM이 랜더링되어 있다

개선된 코딩

이 문제를 해결하기 위하여 스크롤로 노출되는 영역만 페이지번호를 출력하도록 고칠 것이다. 이를 Virtual Scroll이라는 기법이라고 하는데, 이를 위해선 모든 페이지 번호의 폭을 동일하게 만들어야한다. 가장 폭이 넓은 마지막 페이지 버튼의 폭을 구하고, 스크롤 내부에 있는 DOM의 넓이를 ‘가장 넓은 페이지의 폭 x 페이지 수'로 만들어서 비어있지만 스크롤은 가능한 상태로 만든다.

이후에 스크롤이 발생할 때마다 현재 노출된 스크롤의 좌표를 구해서, 좌표에 해당되는 페이지 번호들을 계산하고 화면에 position:absolute를 이용하여 랜더링해주면 된다. 이렇게 하면 어떠한 경우에도 랜더링되는 DOM의 수가 몇 개애 불과하므로, 프리징 현상 등이 발생하지 않게 된다.

Image for post
Image for post
딱 스크롤되는 영역만 표시하도록 하여 최소한의 DOM만 유지한다

이렇게 해서 성능 문제는 해결되었다. 다만 짤림 방지를 위하여 가장 폭이 넓은 버튼을 기준으로 통일하였기 때문에, 총 페이지가 많아질수록 1자리수 버튼들의 폭이 너무 넓어진다는 것이다.

Image for post
Image for post
Virtual Scroll 고정폭 특성상 총 페이지가 커질수록 한 자릿수의 간격은 낭비된다.

더 개선된 코딩

마지막으로 손을 봐주자. Virtual Scroll을 하면서도 각 버튼의 내부 자릿수에 맞추어서 낭비되는 공간이 없도록 해보자.

표시되는 스크롤 영역을 좌표를 넣으면, 해당 공간에 표시되어야할 페이지 번호들을 가 자릿수에 맞춰서 예측하여 반환하면 된다.

1 ~ 9까지의 DOM width,
10 ~ 99까지의 DOM width,
100 ~ 999까지의 DOM width …

각 자릿수별 폭을 구했다면, 특정 좌표에 있어야할 페이지를 구하거나, 반대로 특정 페이지의 좌표 값을 구할 수 있게 된다.

ex) 15페이지의 좌표값 : 1~9까지 한 자릿 수 넓이 x 9개 + 10~15까지 두 자릿 수 넓이 x 16개

소스 및 스타일

간략한 버전

아래는 Codepen에 실제 동작하는 코드들이 있다(모듈화는 차후에 공개할예정이다). 별도의 의존성은 없기에 커스텀이 어렵지는 않다. 스타일을 커스텀하려면 DOM의 골격과 class명만 유지하고 원하는 것을 덧붙이면 된다.

기본 버전 : https://codepen.io/zidell/pen/OJVbdRK
Image for post
Image for post
부트스트랩4 버전 : https://codepen.io/zidell/pen/ZEGeaEJ
Image for post
Image for post
시멘틱UI 버전 : https://codepen.io/zidell/pen/QWbpOJO

마무리

모바일 사용환경에서는 대세는 피드 형식이다. 그리고 이 피드 형식에는 페이지네이션이라는 컴포넌트를 사용하지 않고 ‘더 보기' 혹은 ‘무한스크롤’로 계속 다음 페이지를 아래에 더 불러오는 방식을 취한다.

아카이빙보다 스트림 성격이 강한 일상의 데이터에는 이렇게 최신 위주의 사용자 경험이 옳다. 하지만 서버 랜더링 중심이거나 방대한 데이터를 아카이빙하고 이를 살펴보는 방식에서는 페이지네이션 방식이 더 적합할 수 있다. 페이지네이션은 시계열의 축을 사용자가 자유롭게 건너 띌 수 있고(따라서 일종의 이진트리 검색 방법도 가능), 일시적이지만 고유의 URL을 통해 바로가기도 가능해진다.

각 자료 유형에 따라 사용자에게 어떤 탐색 방법이 더 적합한가 생각해보고, 페이지네이션이 필요한 상황에서는 이 방법을 사용해보길 추천한다.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store