Next.js と TypeScript で、Emotion Media Queries を扱う

TwitterFacebookHatena

TL;DR

この記事では、Next.js と TypeScript を用いて、Emotion Media Queries を使う方法を説明します。Media Queries を活用することで、異なるデバイスサイズに対応したレスポンシブなデザインを実現できます。

開発環境 バージョン
Next.js 13.4.3
TypeScript 5.0.4
Emotion 11.11.0
React 18.2.0

Media Queries とは?

Media Queries は CSS の一部で、デバイスの特性や状況に基づいてスタイルを適用するための技術です。例えば、スクリーンの幅や高さ、方向(ランドスケープまたはポートレート)、解像度などに応じて異なるスタイルを適用することができます。これにより、ある範囲のビューポートサイズで特定のスタイルを適用することが可能になり、レスポンシブデザインを実現できます。

Next.js での Media Queries の使い方

Next.js では、Emotion を使って Media Queries を使用することができます。ここではその基本的な使用方法をお見せします。

以下の例では、useMediaQuery というカスタムフックを作成し、ビューポートの幅が一定の値より大きいかどうかを判定しています。

// /hooks/useMediaQuery.tsx

import { useEffect, useState } from 'react'

type UseMediaQueryType = (width: number) => boolean

const useMediaQuery: UseMediaQueryType = (width) => {
  const [targetReached, setTargetReached] = useState(false)

  const updateTarget = () => {
    setTargetReached(window.innerWidth > width)
  }

  useEffect(() => {
    updateTarget()
    window.addEventListener('resize', updateTarget)
    return () => window.removeEventListener('resize', updateTarget)
  }, [])

  return targetReached
}

export default useMediaQuery

次に、このフックを使って、コンポーネントのスタイルを動的に変更する方法をお見せします。

// /components/DynamicStyledComponent.tsx

import { css } from '@emotion/react'
import useMediaQuery from '../hooks/useMediaQuery'

type Props = {
  text: string
}

const DynamicStyledComponent = ({ text }: Props) => {
  const isDesktop = useMediaQuery(768)

  return (
    <div
      css={css`
        color: ${isDesktop ? 'blue' : 'red'};
      `}
    >
      {text}
    </div>
  )
}

export default DynamicStyledComponent

上記のコンポーネントは、ビューポートの幅が 768px より大きい場合にはテキストの色を青に、それ以外の場合には赤に設定します。

レスポンシブデザインの実装

さらに、Media Queries を使ってレスポンシブデザインを実装する方法について見てみましょう。以下は、スマートフォン、タブレット、デスクトップで異なるスタイルを適用するための一例です。

// /components/ResponsiveComponent.tsx

import { css } from '@emotion/react'
import useMediaQuery from '../hooks/useMediaQuery'

type Props = {
  content: string
}

const ResponsiveComponent = ({ content }: Props) => {
  const isTablet = useMediaQuery(768)
  const isDesktop = useMediaQuery(1024)

  return (
    <div
      css={css`
        color: ${isDesktop ? 'blue' : isTablet ? 'green' : 'red'};
        font-size: ${isDesktop ? '2em' : isTablet ? '1.5em' : '1em'};
      `}
    >
      {content}
    </div>
  )
}

export default ResponsiveComponent

上記のコンポーネントでは、ビューポートの幅に応じてテキストの色とサイズを変更しています。

styled を使う

styled は、Emotion ライブラリの一部であり、JavaScript 内部で CSS を記述し、それを React コンポーネントに適用するためのツールです。テンプレートリテラルを使用して CSS を記述し、それを指定した HTML タグや React コンポーネントに適用することで、スタイリングされた新しいコンポーネントを作成します。この結果、スタイルの再利用と一貫性が向上し、スタイルの管理が容易になります。

@emotion/styled モジュールを使用すると、コンポーネントスタイルをより明確に分離して管理することができます。以下に、styled を使用して Emotion でメディアクエリを実装する例をお見せします。

import styled from '@emotion/styled'

const StyledParagraph = styled.p`
  font-size: 30px;

  @media (min-width: 420px) {
    font-size: 50px;
  }
`

export const ExampleComponent = () => {
  return <StyledParagraph>Some text!</StyledParagraph>
}

このコードでは、styled.p を使って新しいスタイリングされたパラグラフコンポーネント StyledParagraph を作成しています。これは CSS 文字列テンプレートリテラル内でメディアクエリを含むことができます。StyledParagraph はビューポート幅が 420px 以上の場合に font-size50px に変更します。

最後に、新しく作成した StyledParagraph コンポーネントを ExampleComponent 内部で使っています。これにより、ビューポート幅に応じて動的にサイズ変更するテキストを表示できます。

このように、styled を使うと、CSS を JavaScript コードから分離し、より一貫性のあるスタイリングを実現できます。

Next.js と TypeScript で、Emotion Media Queries を扱う