반응형 스타일링

@coldsurfers/ocean-road는 Emotion 기반의 media 유틸리티를 제공합니다. styled() 컴포넌트 내에서 미디어 쿼리를 간결하게 작성할 수 있습니다.

브레이크포인트

모든 브레이크포인트는 max-width 기반(데스크탑 우선)입니다.

max-width 주요 대상
small 576px 소형 모바일
medium 768px 모바일 / 태블릿 세로
large 992px 태블릿 가로
x-large 1280px 소형 데스크탑
xx-large 1460px 중형 데스크탑

기본 사용법

import styled from '@emotion/styled'
import { css } from '@emotion/react'
import { media } from '@coldsurfers/ocean-road'

const Card = styled.div`
  padding: 2rem;

  ${media['x-large'](css`
    padding: 1.5rem;
  `)}

  ${media.medium(css`
    padding: 1rem;
  `)}

  ${media.small(css`
    padding: 0.75rem;
  `)}
`

Text 컴포넌트와 함께 사용

styled(Text)와 조합하면 반응형 타이포그래피를 정의할 수 있습니다.

import styled from '@emotion/styled'
import { css } from '@emotion/react'
import { Text, media } from '@coldsurfers/ocean-road'

const CollectionItemTitle = styled(Text)`
  font-size: 1.25rem;
  font-weight: bold;
  overflow-wrap: break-word;
  white-space: normal;
  margin-top: 1rem;
  margin-bottom: 0;

  ${media['x-large'](css`
    font-size: 1rem;
  `)}

  ${media.medium(css`
    font-size: 0.9rem;
    margin-top: 0.5rem;
  `)}
`

// 사용
<CollectionItemTitle as="h3">{title}</CollectionItemTitle>

breakpoints 직접 사용

breakpoints 객체를 직접 import하면 숫자 값을 참조할 수 있습니다. Emotion 외의 맥락(예: JS 조건 분기, window.matchMedia, 커스텀 훅)에서 브레이크포인트를 재사용할 때 유용합니다.

import { breakpoints } from '@coldsurfers/ocean-road'

// breakpoints.medium === 768
const isMobile = window.innerWidth <= breakpoints.medium

// 커스텀 미디어 쿼리 문자열 생성
const mq = `@media (max-width: ${breakpoints['x-large']}px)`

동작 방식

media.medium(styles)는 다음 미디어 쿼리를 생성합니다:

@media (max-width: 768px) {
  /* styles */
}

데스크탑 우선 방식이므로, 기본 스타일을 가장 넓은 화면 기준으로 작성하고 좁아질수록 override합니다.

const Title = styled(Text)`
  font-size: 2rem;          /* 기본: 데스크탑 */

  ${media['x-large'](css`
    font-size: 1.75rem;     /* ≤ 1280px */
  `)}

  ${media.large(css`
    font-size: 1.5rem;      /* ≤ 992px */
  `)}

  ${media.medium(css`
    font-size: 1.25rem;     /* ≤ 768px */
  `)}

  ${media.small(css`
    font-size: 1rem;        /* ≤ 576px */
  `)}
`