English | 日本語
Important
v3 には破壊的変更が含まれます。
- 参考: v2 から v3 への移行ガイド
- 参考: v1 から v3 への移行ガイド
v2 および v1 もメンテナンスが継続されるため、引き続き使用可能です。
Viewport Extra は、ビューポートの最小幅および最大幅の設定を可能にするライブラリです。これにより、スタイリング時に考慮すべきビューポートの範囲を狭めることができます。
たとえば、幅 412px のページを、ビューポート幅 360px のモバイル向けブラウザ (例: 縦向きの Galaxy S24 上の Chrome) で表示すると、横方向のスクロールが発生してしまいます。これは、412px 未満のビューポート幅のためにスタイルを追加することで解決できますが、その作業は面倒です。しかし、Viewport Extra でビューポートの最小幅を 412px に設定すれば、そのページは 360px にぴったり収まるように縮小され、横方向のスクロールが発生しません。スタイルを追加することなく、簡単に解決できます。
ページの拡大・縮小は、<meta name="viewport"> 要素の content 属性の書き換えにより行われます。
Viewport Extra は、<script async> 要素や import() 構文による非同期の読み込みに対応し、ページ内の他の処理を妨げません。また、他のパッケージに依存せず、標準的なビルドで 1KB 未満 (Brotli 圧縮時) と非常に軽量です。
- 小さなビューポート幅でページを縮小する
- 大きなビューポート幅でページを拡大する
- メディアクエリごとに異なる最小幅・最大幅を設定する
- ビューポート幅が変わるときにもページを拡大・縮小する
- レガシーな環境でもページを拡大・縮小する
<meta name="viewport-extra">要素を使わずにページを拡大・縮小する
次のコードを含むページは、ビューポート幅が 412px 未満のモバイル向けブラウザでは縮小され、それ以外のブラウザでは縮小されません。縮小すべきかどうかの判定は、ページが表示されるときに一度だけ行われます (参考) 。
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="viewport-extra" content="minimum-width=412">
<script async src="https://cdn.jsdelivr.net/npm/viewport-extra@3.0.0/dist/immediate/viewport-extra.min.js"></script>import("viewport-extra").then(({ apply }) => {
apply([{ content: { minimumWidth: 412 } }])
})initial-scale=0.8737864077669902,width=412
initial-scale=0.9538834951456311,width=412
initial-scale=1,width=device-width
initial-scale=1,width=device-width
initial-scale=1,width=device-width
次のコードを含むページは、ビューポート幅が 393px を超えるモバイル向けブラウザでは拡大され、それ以外のブラウザでは拡大されません。拡大すべきかどうかの判定は、ページが表示されるときに一度だけ行われます (参考) 。
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="viewport-extra" content="maximum-width=393">
<script async src="https://cdn.jsdelivr.net/npm/viewport-extra@3.0.0/dist/immediate/viewport-extra.min.js"></script>import("viewport-extra").then(({ apply }) => {
apply([{ content: { maximumWidth: 393 } }])
})initial-scale=1,width=device-width
initial-scale=1,width=device-width
initial-scale=1.0483460559796438,width=393
initial-scale=1.8676844783715012,width=393
initial-scale=2.6055979643765905,width=393
次のコードを含むページは、ビューポート幅が 412px 未満または 744px 以上 1024px 未満のモバイル向けブラウザでは縮小され、それ以外のブラウザでは縮小されません。縮小すべきかどうかの判定は、ページが表示されるときに一度だけ行われます (参考) 。
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="viewport-extra" content="minimum-width=412">
<meta name="viewport-extra" content="minimum-width=1024" data-media="(min-width: 744px)">
<script async src="https://cdn.jsdelivr.net/npm/viewport-extra@3.0.0/dist/immediate/viewport-extra.min.js"></script>import("viewport-extra").then(({ apply }) => {
apply([
{ content: { minimumWidth: 412 } },
{ content: { minimumWidth: 1024 }, media: "(min-width: 744px)" },
])
})initial-scale=0.8737864077669902,width=412
initial-scale=1,width=device-width
initial-scale=0.7265625,width=1024
initial-scale=1,width=device-width
次のコードを含むページは、表示されるときだけでなく、ビューポート幅が変わるときにも拡大・縮小すべきかどうかの判定を行います。モバイル端末の縦向き・横向きの切り替えや、タブレットの画面分割が想定される場合に有用です。
<meta name="viewport" content="width=device-width,initial-scale=1">
<script
async
src="https://cdn.jsdelivr.net/npm/viewport-extra@3.0.0/dist/immediate/viewport-extra.min.js"
id="viewport-extra-script"
></script>
<script>
const updateViewportMetaEl = () => {
// 無限リサイズを回避する
new ResizeObserver((_, observer) => {
observer.unobserve(document.documentElement)
window.addEventListener("resize", updateViewportMetaEl, { once: true })
}).observe(document.documentElement)
ViewportExtra.apply([
{ content: { minimumWidth: 412 } },
{ content: { minimumWidth: 744 }, media: "(min-width: 640px)" },
])
}
if (window.ViewportExtra) {
updateViewportMetaEl()
} else {
document
.getElementById("viewport-extra-script")
.addEventListener("load", updateViewportMetaEl)
}
</script>import("viewport-extra").then(({ apply }) => {
const updateViewportMetaEl = () => {
// 無限リサイズを回避する
new ResizeObserver((_, observer) => {
observer.unobserve(document.documentElement)
window.addEventListener("resize", updateViewportMetaEl, { once: true })
}).observe(document.documentElement)
apply([
{ content: { minimumWidth: 412 } },
{ content: { minimumWidth: 744 }, media: "(min-width: 640px)" },
])
}
updateViewportMetaEl()
})initial-scale=0.9538834951456311,width=412
initial-scale=0.9865591397849462,width=744
ここまでに使用している標準的なビルドには、ES2021 の構文、および Viewport Extra v3.0.0 公開時点で Web Platform Baseline の Widely Available ステージにある機能が含まれます。これらをサポートしない環境 (例: iOS Safari < 16, Android Chrome < 108) でも Viewport Extra を動作させるためには、es5 ビルドを使用します (参考) 。
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="viewport-extra" content="minimum-width=412">
<script async src="https://cdn.jsdelivr.net/npm/viewport-extra@3.0.0/dist/immediate/es5/viewport-extra.min.js"></script>import("viewport-extra/immediate/es5").then(({ apply }) => {
apply([{ content: { minimumWidth: 412 } }])
})initial-scale=0.9101941747572816,width=412
initial-scale=1,width=device-width
次のコードを含むページは、<meta name="viewport-extra"> 要素を使用した実装と同様に動作します。
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="viewport" data-extra-content="minimum-width=412">
<meta name="viewport" data-extra-content="minimum-width=1024" data-extra-media="(min-width: 744px)">
<script async src="https://cdn.jsdelivr.net/npm/viewport-extra@3.0.0/dist/immediate/viewport-extra.min.js"></script>initial-scale=0.8737864077669902,width=412
initial-scale=1,width=device-width
initial-scale=0.7265625,width=1024
initial-scale=1,width=device-width
-
minimum-width/maximum-widthの代わりに、min-width/max-widthを使用できます。ただし、両方が混在する場合の動作は保証されないため、どちらか一方に統一する必要があります。<meta name="viewport-extra" content="min-width=412,max-width=640">
同様に、
minimumWidth/maximumWidthの代わりに、minWidth/maxWidthを使用できます。これらも、両方が混在する場合の動作は保証されないため、どちらか一方に統一する必要があります。apply([{ content: { minWidth: 412, maxWidth: 640 } }])
-
次のスタイルを併用することを推奨します。小さなモバイル端末における、ブラウザによる意図しないテキストサイズの調整を防ぎます (参考) 。
body { -webkit-text-size-adjust: 100%; }
-
デスクトップ向けブラウザの開発者ツールで動作を確認する場合、Viewport Extra を使用するページへ移動するよりも先に、モバイル端末のシミュレーションを有効化し、ビューポートを目的のサイズに設定しておく必要があります。順番が逆である場合、ブラウザが
<meta name="viewport">要素のinitial-scaleの設定を無視してしまう状態となります。これは、開発者ツールのシミュレーションに特有の現象であり、実際のモバイル向けブラウザでは発生しません。

