旧ブログ(ISSEN)から移行しました

【Next.js】viewportを使って小さい画面幅のレスポンシブ対応をする方法

【Next.js】viewportを使って小さい画面幅のレスポンシブ対応をする方法

西原月熙
西原月熙4分で読めます

はじめに

こんにちは、株式会社TOKOSのツキヤです!
今回は、フロントエンドを実装する時に気をつける「レスポンシブ対応」について、特に小さい画面幅の際の効果的な対応方法を説明します✍️
どうしても小さい画面幅のレスポンシブ対応がしづらい場合はこの記事が役立つかもです✨

本記事はNext.jsで記述しますが、素のReactやRemix等他のReactフレームワークでも対応可能なはずなのでぜひ参考にしてみてください💪

対象読者・前提

  • Next.js (React) で小さい画面幅の対応をしたい方
  • viewportについて知りたい方

今回は、Next.jsのApp Routerを用いて、410px以下の画面幅を対応するものとします!

実装方針

実装方針としては、「特定のpx以下の場合はviewportのwidthを固定にする」というものです!
上記方針とそれに関わる知識の説明をサクッとします!

viewportとは?

HTMLを記述したことがある人なら、<head>タグの中で1度は見かけたことがある

<meta name="viewport" content="width=device-width, initial-scale=1.0" />

↑ このname="viewport"となってる<meta>タグを本記事ではviewportと呼んでいます!
これは、HTMLがデバイス上でどのように表示されるかをブラウザに指示するためのタグです!
このmetaタグがあることで、ウェブページは異なる画面サイズ(デバイス)に適応し、見やすくなります。

特に理解しておいてほしいのが、 content="width=device-widthの部分です!
この設定は、ビューポートの幅(ページが表示される領域の幅)を、デバイスの画面幅に合わせるというものです。この設定により、ページはデバイスの画面幅に基づいて適切に縮尺され、ユーザーが画面をズームしなくても内容全体を見ることができるようになります✨

ツキヤツキヤ

当たり前だけど、widthが390pxのiPhone 14で見たら390pxに、1440pxのMacbookで見たら1440pxになるということだね!

initial-scale=1.0は、ページにアクセスした時のズームの具合です! これは100%(デフォルト)
であってほしいので、ほとんどのサイトで1.0が設定されているはずです。

実装方法

上記を理解した上で、改めて今回の方針である「特定のpx以下の場合はviewportのwidthを固定にする」という実装を行います!
と言っても簡単で、1つコンポーネントを作るだけです!
今回は適当なパスにControlViewport.tsxというコンポーネントを作成します。

src/app/_components/ControlViewport.tsx
"use client"
 
import { useEffect } from "react"
 
export function ControlViewport(): null {
  useEffect(() => {
    if (typeof window === "undefined") return
    const resizeViewport = () => {
      const viewport = document.querySelector("meta[name=viewport]")
      if (!viewport) return
      viewport.setAttribute(
        "content",
        window.outerWidth > 410
          ? `width=device-width,initial-scale=1.0,maximum-scale=1.0`
          : `width=410,maximum-scale=1.0`,
      )
    }
 
    window.addEventListener("resize", resizeViewport)
    resizeViewport() // 初回のレンダリング時にも実行
    return () => window.removeEventListener("resize", resizeViewport)
  }, [])
 
  return null
}

上記コンポーネントは、 return nullをしているので、UIには特に影響を与えません。

useEffect内で、 document.querySelector("meta[name=viewport]")を使ってmetaタグを取得した後に、 window.outerWidthという現在のブラウザの横幅を取得するメソッドを使って、
・410pxより大きい: width=device-width
・410px以下   : width=410
上記分岐を行い、metaタグにセットし直しているだけです😎

ツキヤツキヤ

アンマウント時のためのクリーンアップ関数も忘れずに!

このコンポーネントをlayout.tsxで呼び出します。

src/app/layout.tsx
import { ControlViewport } from "@/app/_components/ControlViewport"
 
const RootLayout = ({ children }: { children: React.ReactNode }) => (
  <html lang="ja">
    <body>
      <ControlViewport />
      {children}
    </body>
  </html>
)
export default RootLayout

以上で、410px以下の画面幅の場合は等倍で縮尺するようになります!

終わりに

今回は、小さい画面幅に対する簡単なレスポンシブ対応の方法を説明しました!
とは言え、一般的なスマホのサイズ(400px前後)位に対しては普通のレスポンシブ対応をすべきです。
今回の方法は、特に小さな画面幅に対しての実装面でのコストパフォーマンスを考慮に入れた上で実装を検討してみてください🙏

この記事を書いた人

西原月熙
西原月熙

TOKOSのテックリード。上流工程からコーディング、インフラ系まで色々やっている器用貧乏です。最近は特にフロントエンドのキャッチアップに力を入れています💪 好きな音楽はボーカロイドです🤖