LoginSignup
0
1

More than 1 year has passed since last update.

デバイスの画面幅からはみ出している要素を検出する方法(1)

Last updated at Posted at 2022-09-17

レスポンシブ対応のデバッグする際、デバイスの画面幅からはみ出して横スクロールの原因となっている要素がないかJavaScriptを使ってチェックしたい。

デバイスの画面幅の値を取得するには、最初、screen.widthwindow.innerWidthプロパティの値から取ればいいのかなと思っていましたが、それだと実行環境によってはチェックがうまくいかないケースがあるとわかりました。

この記事(前編)は、ブラウザーのレスポンシブデザインモード(RDM)と実機のブラウザーとでデバイスの画面幅がどのように認識されるか、その違いを調べたメモです。

レスポンシブモードと実機での表示の違い

例として、レイアウト幅1200pxのページを画面幅1024pxのiPad Proに表示した場合を取り上げます。

※サンプルのコードはこちら: https://codepen.io/kaz_hashimoto/pen/XWEXRdO

下図は左から順に、Chrome DevToolsからのデバイスモード、Safariのレスポンシブデザインモード、iOSシミュレーターを使って表示した画面です。
fig01.jpg
※画像引用:Photo by Inspirationfeed on Unsplash

デバイスモードやレスポンシブデザインモード(以下、この2つを総称してRDMと表記)で表示した場合、コンテンツが画面幅に収まらないため横スクロールが発生しています。一方、実機1で表示した場合はページ全体が縮小して画面の横幅にフィットして表示されました。

もう1つ大きな違いはメディアクエリの結果です(左端の矢印)。

クエリ RDM 実機
@media (max-width: 1024px) true false

ブラウザーが認識している画面の寸法がRDMと実機とで異なるようです。そこで、このとき画面やビューポートの寸法に関するプロパティの値は何が返されるのかを検証してみました。

以下、デバイスのタイプはすべてiPad Pro (12.9-inch)を使用し、画面の方向は縦とします。デバイスの画面サイズは1024x1366です。また、HTMLにはビューポート属性が指定されているものとします。

html
<meta name="viewport" content="width=device-width, initial-scale=1">

結果

まずはデスクトップ版ブラウザー2のRDMで表示した場合です。表でセルの値が1024pxを超えるものを青色の背景で示しました。
table1.png
Safariだけscreen.widthの値が2560pxになっていますが、これは私が使用しているモニター(iMac 27inch)の画面幅の値(cssピクセル単位)を返してきたようです。

一方、window.innerWidthについては、レイアウト幅の1200pxを返すものと、デバイスの画面幅1024pxを返すものが混在しています。

次に実機で表示した場合です。
table2.png
iOS13以上ではページがフィットして表示されましたが、iOS12ではフィットせずに画面幅から溢れて横スクロールが発生しました。

2つの表からわかるように、iOS12を除き右端のセルの値は常に1024を表示しています。この計算式を使えば、RDMでも実機でも一律にデバイスの画面幅を取得することができそうです。

式1
visualViewport.width * visualViewport.scale

iOSの場合、VisualViewportインターフェイスはiOS13からサポートされました。iOS12以前などvisualViewportをサポートしていない古いブラウザーについてはwindow.innerWidthで代用するしかないかと思います。

MDNの説明によると、window.innerWidthの値はレイアウトビューポートの幅から取られるのが仕様なので、このサンプルの場合、1200pxを返すのが正しいと思われます。

他のケースで検証

式1で画面幅の値が得られるかどうか他のケースで検証してみましょう。

タブを追加した時のサイズ

iPadでタブを追加するとresizeイベントが発生します。下の動画では右側のconsoleに各プロパティの値がどう変化するかを表示しています。

See the Pen Vimeo Player API demo by Kazuhiro Hashimoto (@kaz_hashimoto) on CodePen.

consoleのログにはタイミングごとにラベルを付けました。
table3.png
window.innerWidthvisualViewport.widthの値は共に最初1024pxに設定されますが、画像の読み込みが完了したタイミングで1200pxに変わります。そしてタブを追加してアクティブにした時にresizeイベントが発生し、一旦1024pxに戻った後、少し経ってから1200pxに変わる、という複雑な動きをしています。

一方、visualViewport.width * visualViewport.scaleは常に画面幅の1024pxが得られます。

Split View

次にiPadのSplit Viewで画面を分割した場合です。画面を縦置き・横置き両方やってみます。
fig02_splitview.jpg
まずはSafariのRDMです。SafariのRDMはiPadのSplit View表示もシミュレートできます。
table4.png
screen.widthは相変わらずモニターの画面幅の値を返しますが、visualViewport.width * visualViewport.scaleは、Split Viewで分割された画面の幅が得られます。

次に実機でのSplit Viewです。
table5.png
screen.widthはデバイスの画面幅、window.innerWidthおよびvisualViewport.widthはレイアウト幅(1200px)を返しています。こちらも同様にvisualViewport.width * visualViewport.scaleは、Split Viewで分割された画面の領域の幅が得られます。

まとめ

後で使うため、式1を関数で定義しておきます。

getDeviceWidth()は、ビューポートのスケーリングの影響を取り除いた形でデバイスの画面幅の値(cssピクセル単位)を返します。
※Split Viewで画面を領域に分割している場合、この関数は領域の幅の値を返します

javascript
function getDeviceWidth() {
  if (typeof window.visualViewport === 'undefined') {
    return window.innerWidth;
  }
  const width = visualViewport.width * visualViewport.scale;
  return Math.round(width);
}

後編の記事(2)へ続く。

  1. テストしたのはXcodeのiOSシミュレーターですが説明を簡単にするため本文中は「実機」とみなして表記します。

  2. 使用したブラウザーのバージョン(記事執筆時点)は、Chrome 105, Firefox 104, Safari 15.6.1, Edge 105です。OSはEdgeのみWindows 10、それ以外はmacOS Big Surです。

0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1