IT/React

[React] React-Responsive / 반응형 웹 만들기

라임웨일 2022. 4. 27. 12:58
반응형

1. Responsive Web

반응형 웹이란 태블릿, PC, 모바일 등 다양한 디바이스의 해상도로 접근할 때 불편함이 없는 서비스를 제공하기 위해 디바이스에 맞는 해상도에 따라서 레이아웃과 스타일에 최적화를 해주어 사용자에게 편의성이 높은 UI 화면을 제공합니다.

1-1. Media Query

CSS 2.1부터 미디어 타입으로 단말기 종류에 따라서 다른 스타일을 적용시키는 것이 가능했는데 기기의 특성을 정확히 판단하기가 어려워 많이 사용되지는 않았습니다. CSS 3은 미디어 타입을 개선하여 구체적인 조건을 필요한 스타일을 적용할 수 있도록 확장하였는데 이를 미디어 쿼리라고 합니다.

Syntax

  • only|not
    • only : 뒤의 조건에서 만
    • not : 뒤의 조건을 제외한
  • 미디어 타입
    • all : 모든 미디어 타입
    • aural : 음성 합성 장치
    • braille : 점자 표시 장치
    • handheld : 손으로 들고 다니면서 볼 수 있는 작은 스크린에 대응
    • print : 인쇄 용도
    • projection : 프로젝터
    • screen : 컴퓨터 스크린
    • tty : 디스플레이 능력이 한정된 릴랙스, 터미널, 수동 이동 장치 등 고정된 글자를 사용하는 미디어
    • tv : 음성과 영상이 동시 출력되는 장치
    • embrossed : 페이지에 인쇄된 점자 표시 장치
  • 속성
    • width : 웹 페이지의 가로길이
    • height : 웹 페이지의 세로 길이
    • device-width : 단말기의 가로길이
    • device-height : 단말기의 세로 길이
    • orientation : width와 height을 구해
      width > height 일 경우 landscape
      height > width 일 경우 portrait
    • aspect-ratio : width / height 비율
    • device-aspect-ratio : 단말기의 물리적인 화면 비율
    • color-index : 단말기에서 사용하는 최대 색상 수
    • monochrom : 흑백 컬러만을 사용하는 단말기에서 흰색과 검은색 사이의 단계
    • resolution : 지원하는 해상도를 판단
    • color : 단말기에서 사용하는 최대 색상 수의 비트 수
      (2의 지수를 뜻한다) ex) 1 은 2, 2는 4, 3 은 8

1-2. Fluid Grid

그리드의 폭을 고정 값이 아닌 em 또는 % 의 값으로 설정하는 것을 뜻하며 가로 폭의 길이의 변화에 따라서 칼럼의 크기가 상대적으로 변하게 하는 방법입니다. 레이아웃에는 변화가 없을 수 있으므로 폭이 많이 좁은 모바일에서 큰 효과를 볼 수 없을 수 있습니다.

1-3. Liquid Layouts

유동형 그리드와 같이 반응형 웹 기법 중 하나로 레이아웃 크기를 유동형 그리드와 같이 상대적 단위로 지정하여 웹의 크기에 따라 유동적으로 변화를 줍니다. 반응형 그리드와 같이 미디어 쿼리를 사용하여 일정 크기가 되면 레이아웃 구조를 바꾸어 줍니다.

2. in React

React에서도 반응형을 대응하기 위해 Medai Query를 이용하여 대응할 수도 있지만 보다 React에서는 보다 편리한 npm인 react-responsive을 제공하기에 react-responsive의 훅을 이용해 구현하는 방법을 알아보려고 합니다.

2-1. react-responsive

 

react-responsive

Media queries in react for responsive design. Latest version: 9.0.0-beta.6, last published: 3 months ago. Start using react-responsive in your project by running `npm i react-responsive`. There are 893 other projects in the npm registry using react-respons

www.npmjs.com

타입스크립트를 사용할 경우 : npm install --save @types/react-responsive

  • react-responsive 모듈 설치
  • npm install react-responsive
  • typescript를 사용하는 경우 추가 설치
  • npm install @types/react-responsive

2-2. useMediaQuery

import React from 'react'
import { useMediaQuery } from 'react-responsive'
 
const Example = () => {
  const isDesktopOrLaptop = useMediaQuery({ minDeviceWidth: 1224 })
  const isBigScreen = useMediaQuery({ minDeviceWidth: 1824 })
  const isTabletOrMobile = useMediaQuery({ maxWidth: 1224 })
  const isTabletOrMobileDevice = useMediaQuery({ maxDeviceWidth: 1224 })
  const isPortrait = useMediaQuery({ orientation: 'portrait' })
  const isRetina = useMediaQuery({ minResolution: '2dppx' })
 
  return (
    <div>
      ...
    </div>
  )
}

react-responsive에서 제공하는 useMediaQuery 훅으로 공식 문서의 예제와 같이 위의 내용을 작성해서 변수를 사용할 수 있습니다. 해당 변수는 조건에 맞는지 아닌지에 대한 true / false 가 들어가게 되는데. 특정 상황에서만 출력을 하도록 하고 싶다면 아래와 같은 예제를 만들 수 있습니다.

import { useMediaQuery } from 'react-responsive'
 
const Example = () => {
  const isDesktopOrLaptop = useMediaQuery(
     { minDeviceWidth: 1224 },
     { deviceWidth: 1600 } // `device` prop
  )
 
  return (
    <div>
      {isDesktopOrLaptop &&
        <p>
          this will always get rendered even if device is shorter than 1224px,
          that's because we overrode device settings with 'deviceWidth: 1600'.
        </p>
      }
    </div>
  )
}

Easy Mode

공식 문서에 Context를 사용하는 방법 / onChange callback을 사용하는 방법이 있으므로 보는 것도 좋을 것 같습니다.

맨 아래에 있는 내용 중 제일 유용할 것 같은 예제입니다.

import { useMediaQuery } from 'react-responsive'
 
const Desktop = ({ children }) => {
  const isDesktop = useMediaQuery({ minWidth: 992 })
  return isDesktop ? children : null
}
const Tablet = ({ children }) => {
  const isTablet = useMediaQuery({ minWidth: 768, maxWidth: 991 })
  return isTablet ? children : null
}
const Mobile = ({ children }) => {
  const isMobile = useMediaQuery({ maxWidth: 767 })
  return isMobile ? children : null
}
const Default = ({ children }) => {
  const isNotMobile = useMediaQuery({ minWidth: 768 })
  return isNotMobile ? children : null
}
 
const Example = () => (
  <div>
    <Desktop>Desktop or laptop</Desktop>
    <Tablet>Tablet</Tablet>
    <Mobile>Mobile</Mobile>
    <Default>Not mobile (desktop or laptop or tablet)</Default>
  </div>
)
 
export default Example

 

 

위와 같은 방법도 있지만, 사실 가장 좋은 방법은 hooks로 하나의 컴포넌트 파일을 만들어서 사용할 수도 있습니다.

import React from "react"
import { useMediaQuery } from "react-responsive"

export const Mobile = ({ children }) => {
  const isMobile = useMediaQuery({
    query: "(max-width:768px)"
  });
  return <>{isMobile && children}</>
}

export const Pc = ({ children }) => {
  const isPc = useMediaQuery({
    query: "(min-width:769px)"
  });
  return <>{isPc && children}</>
}
function App() {
  return (
    <>
      <Mobile>mobile</Mobile>
      <Pc>pc</Pc>
    </>
  )
}

 

출처 :

 

반응형