Adaptive Design 구현하기

적응형 디자인을 위한 코딩

Breakpoint 잡기

반응형 디자인은 모든 레이아웃을 고려해야 하기에 구현이 부담스럽다. 그렇다면 적당한 breakpoint를 찾아 몇 단계로 나눠보자. breakpoint는 어떻게 잡을 것이고 몇 단계로 나누는게 적절할까?

이런저런 자료를 검색해보았고, 이 글을 보고 감탄했다. 특정 디바이스에 맞춰 이 디바이스까지는 이 디자인! 이 아니라, 그 사이의 어떤 지점을 잡는게 더욱 합리적인 결정이라는 이야기다. 이 글에 따르면, 600, 900, 1200을 기준으로 mobile, tablet-portrait, tablet-landscpae, desktop을 나눌 수 있다. 그대로 채택했다. 대부분의 모바일 디바이스가 360 이상 임을 고려해 360까지 지원하는걸 목표로 삼았으나, 아직(2021년) 현역으로 지원받고 있는 iPhone SE(320)를 고려해, tooSmall 이라는 구분자를 하나 더 두었다. 또, 글에서는 1800 이상의(ex. iMac) 디바이스에 대한 고려도 하는게 좋다는 듯 말했지만, 그건 내가 아이맥을 산 뒤의 일로 미루기로 했다 ;)

구현하기

구현 과정에서의 난점은 몇 가지가 있었다.

첫째로, 이 구현이 CSS로 엘리먼트의 배치나 사이즈를 변경하는 것으로 이루어질게 아니라, 컴포넌트의 구조가 뒤바뀔 정도의 변화가 있다면 (ex. 모바일에서는 헤더에 사이드바가 나온다던가) 그 구현을 위해서는 컴포넌트를 분리하는게 낫다고 생각했고, 그러려면 지금 보여주는 화면이 어떤 사이즈의 화면인지를 JS쪽에서도 알 수 있어야 했다.

그런데 조금만 다시 생각해보자. 나는 styled-components와 같은 CSS-in-JS를 주로 쓰기 때문에, JS에서만 알게 되면 CSS로 해당 정보를 넘겨줄 수 있었다. ThemeProvider 같은걸로. 여기에서 react-responsive를 사용해 이 정보를 얻어왔고, ResponsiveContext(for script), ThemeProvider(for style)에 동일한 값을 넘겨줄 수 있다.

두 번째 문제로, Next.js를 사용하면서, 서버 사이드에서 렌더링 될 때는 어떤 상태로 렌더링할 것인가를 결정해야 하는 문제가 있다. 앞서 사용한 react-responsiveuseMediaQuery라는 훅을 제공하는데, 이 훅은 서버사이드 렌더링 시 모든 쿼리에 false를 반환한다. 이 라이브러리에서 제공해주는 Context를 통해 서버사이드 렌더링 시의 width를 설정할 수 있지만, 이 경우 resize 이벤트 감지 및 업데이트까지 개발자의 몫이 된다. 때문에, 가장 사용자가 가장 자주 방문할 것 같은 타입(모바일)이면서도 네트워크 속도가 느릴 수 있는 상태-를 서버사이드 상태에서의 렌더링 시 렌더링하는 것으로 결정했다.

그러나 문제가 완전히 해결된 것은 아니었다. 데스크탑에서 접속한 사용자에게, 깜빡임이 발생했다. SSG를 버리고 SSR로 전향, userAgent를 확인해서 적절하게 내려주는 방법도 있을테지만, 조금 더 쉽게 가기로 했다. 최초 렌더링 시 visibility: hidden; 상태로 보여주다가, 클라이언트에서 렌더링 되며 스크린 사이즈를 측정하게 되는 순간에 visibility: visible;로 변경하는 것이다.

이 문제를 싹 묶어 HOC로 구현했다.

결론 및 요약

4가지 적응형 모델로 구현을 하다보니, mobile / tabletP 와, tabletL / desktop 에서 비슷한 스타일을 사용하게 되는 일이 잦았다. 그래서 small / large 라는 그룹도 하나 더 두기로 했다. 결론적으로 나온 모델이 이 페이지 상단에 렌더링된 모델이다. SVG로 그려진 이 도표는 현재 당신이 보고 있는 화면 사이즈에 따라 반응한다. 현재 화면은 빨갛게 칠해진 플래그가 활성화 된 상태라는 표시이다.