はじめに
最近、Next.js 13以降のApp Routerでviewportの設定について調べていたら、まだ従来のmetaタグで書いてた自分に気づいた😅
<!-- 今までやってた方法 -->
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0">
でも実際は、Next.jsではオブジェクトで書く方が推奨されてるらしい。
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
userScalable: false,
}
なんで今までこれを知らなかったんだろう...ということで、調べてみたら納得できる理由があったのでまとめる。
なぜオブジェクト形式が良いのか
1. 型安全性が効く
これは大きい。TypeScriptを使ってる意味がある。
// ✅ TypeScriptで型チェックされる
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1, // プロパティ名をtypoしたらコンパイルエラー
}
// ❌ 文字列なのでtypoに気づきにくい
content="width=device-width,initial-scale=1.0,maxmium-scale=1.0"
// ↑ 気づかないtypo
実装するときは、実行時エラーよりコンパイル時エラーの方が圧倒的に楽。
2. 設定が読みやすい
一目で何を設定してるかわかる。
// ✅ 何を設定してるか一目瞭然
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
userScalable: false,
themeColor: '#000000',
}
// ❌ 長い文字列で何設定してるかパッと見わからない
content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no,theme-color=#000000"
コードレビューの時も、オブジェクト形式の方が変更点が分かりやすい。
3. メタデータを一箇所で管理できる
Next.jsの設計思想に沿ってる。
// ✅ layout.tsxで一元管理
export const metadata: Metadata = {
title: "My App",
description: "...",
// その他のメタデータ
}
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
}
// ❌ メタデータが分散
export const metadata: Metadata = { ... }
// + どこか別の場所にviewportのmetaタグ
4. Next.jsの自動最適化が効く
これは知らなかった。Next.jsが裏で色々やってくれてる。
- 重複排除: 同じメタデータが複数定義されても自動で重複を排除
- 順序最適化: SEOに最適な順序でHTMLに挿入
- エラーハンドリング: 不正な値を自動検出
5. フレームワークの規約に従う
これは大事な考え方だと思う。
フレームワークが「こうやって書いてね」と言ってるなら、それに従った方が長期的に保守しやすい。チーム開発でも一貫性が保てる。
実際の書き方
Before(従来の方法)
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="ja">
<head>
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0" />
</head>
<body>{children}</body>
</html>
)
}
After(推奨される方法)
import type { Metadata, Viewport } from "next"
export const metadata: Metadata = {
title: "My App",
description: "...",
}
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
userScalable: false,
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="ja">
<body>{children}</body>
</html>
)
}
スッキリした!
よく使うViewportの設定
// 基本的な設定
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
}
// iOSでinputフォーカス時のズームを防ぐ
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
userScalable: false,
}
// PWA対応も含める場合
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
userScalable: false,
themeColor: '#000000',
}
まとめ
今まで何も考えずに従来のmetaタグでやってたけど、Next.js 13以降のApp Routerを使うならオブジェクト形式にした方が良いことがわかった。
理由をまとめると:
- 型安全性: TypeScriptの恩恵を受けられる
- 可読性: 設定内容が分かりやすい
- 保守性: 一箇所で管理できる
- 最適化: Next.jsの自動最適化が効く
- 一貫性: フレームワークの規約に従える
「フレームワークの規約に従う」というのが一番しっくりきた。