이제는 어느 사이트를 가든 반응형 페이지가 디폴트로 되어 있다. 항상 고정적인 레이아웃을 가지게 되면 모바일 디바이스부터 데스크톱까지 다양한 환경이 있음에도 불구하고 같은 화면을 보게 되는 거니 사용자 경험상으로 좋지 않다. 그렇기에 서비스를 디자인 할 때는 반응형으로 많이 신경쓰는 편이다.

반응형 디자인이란?

웹 페이지의 디자인과 레이아웃이 모든 화면 크기에 자동으로 맞춰지는 디자인이다. 데스크탑에서 페이지를 늘렸다 줄였다 하면 이에 맞춰서 화면의 디자인이 바뀌는게 반응형 디자인이다.

다른 방식의 유연한 웹 디자인 기술로는 적응형 디자인이 있다. 적응형 디자인의 경우 웹 페이지에서 감지된 기기를 기반으로 미리 만드레어진 정적인 레이아웃을 불러오는 것으로 각 화면 크기마다 이에 맞는 레이아웃을 따로 디자인을 해야 한다. 이 방식은 각각 저마다의 장단점을 지닌다.

반응형 디자인적응형 디자인
장점모든 플랫폼에서 일관된 콘텐츠 경험을 제공
보편적이지 않은 화면 크기에서도 이에 맞춘 레이아웃 제공
각 플랫폼에 맞추어 제공되는 보다 나은 사용자 경험
원하는 기기에 맞게 최적화된 디자인을 할 수 있는 고성능 작업 수행
단점렌더링 방식의 통제가 까다로움
동적 콘텐츠를 불러오는데 더 많은 작업 요구
일관적이지 않은 콘텐츠가 SEO에 부정적인 작용
하나하나 다 만들어야됨

자바스크립트에서의 미디어쿼리

자바스크립트에는 미디어 쿼리 문자열을 분석하고 이결과를 알려주는 matchMedia라는 브라우저의 전역 객체 메서드가 있다.

if (window.matchMedia("(min-width: 400px)").matches) {
  /* 뷰포트 너비가 400 픽셀 이상 */
} else {
  /* 뷰포트 너비가 400 픽셀 미만 */
}

이와 같이 각 미디어에 맞추어 현재의 미디어 쿼리를 자바스크립트를 통해 관리할 수 있도록 만들어준다. 이를 리액트의 상태와 함께 구분하면 조금 더 야무진 반응형의 관리를 할 수 있다.

모바일과 데스크톱 구분하기

import * as React from "react"
 
const MOBILE_BREAKPOINT = 768
 
export function useIsMobile() {
  const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
 
  React.useEffect(() => {
    const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
    const onChange = () => {
      setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
    }
    mql.addEventListener("change", onChange)
    setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
    return () => mql.removeEventListener("change", onChange)
  }, [])
 
  return !!isMobile
}
 

해당 전역 객체의 matchMedia로 받는 MediaQueryList 객체에 이벤트 핸들러를 등록해놓은 다음 특정 너비가 바뀌었을 때 상태를 바꿈으로써 모바일 상태와 데스크탑 상태로 구분하였다. 나는 여기서 모바일과 데스크톱 환경 정도만 구분한 뒤에, 데스크톱의 경우에는 따로 미디어 쿼리를 추가하는 방식으로 관리를 할 수 있도록 해주는 것이 낫겠다고 생각했다. 디바이스가 달라지면 이에 따라 조금 더 적응형에 가까운 레이아웃을 제공함으로써 디바이스별로 사용자가 이를 편안하게 받아들일 수 있도록 해야 한다고 생각하기 때문이다. 그렇기 때문에 보다 이를 상태로 관리하려고 했다.

"use client";
 
import { useIsMobile } from "@/hooks/use-mobile";
import React from "react";
 
export default function ResponsiveWrapper({
  children,
}: {
  children: React.ReactNode;
}) {
  const mobileEnvironMent = useIsMobile();
  return (
    <body
      className={`${
        mobileEnvironMent ? "모바일 환경 레이아웃" : "데스크탑 화면 레이아웃"
      }  mx-auto relative`}
    >
      {children}
    </body>
  );
}

이런 식으로 body에 아예 레이아웃 css를 다르게 해주는 래퍼를 만들어 엔트리 포인트나 최상단 레이아웃쪽에서 감싸면 최상위에서 디바이스를 감지하고 레이아웃을 변경해주어 편하다.