Help us understand the problem. What is going on with this article?

iOS safari 9.2 で window.innerWidth と viewport の値がズレる

More than 3 years have passed since last update.

レスポンシブデザインのページで、 window.innerWidth の値によって条件分岐するような js を書いていたとき、 iOS だけ条件分岐がうまくいってないことが判明。
ちなみに、 Chrome DevTools で iOS 系のデバイスモードにしているときと Android は 問題なく、iOS 実機及び iOS Simulator でのみ発生していました。

画面幅に関連する値を取得してみる

まずは計測ということで、以下のような HTML を用意して画面幅に関する3つの値、 window.innerWidthscreen.widthdocument.documentElement.clientWidth を取得してみました。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <title>viewport test</title>
</head>
<body>
  <h1>viewport test</h1>
  <p id="text"></p>
  <script>
    window.addEventListener('load', function(){
      function printWidth(){
        document.getElementById('text').innerHTML = 
        'window.innerWidth: '+window.innerWidth+
        '<br>screen.width: '+screen.width+
        '<br>documentElement.clientWidth: '+document.documentElement.clientWidth;
      }
      printWidth();
    });
  </script>
</body>
</html>

iOS simulator の結果(iOS9.2 iPhone6)

simulator_1.png

window.innerWidth が 980 と、document.documentElement.clientWidth の 375 とは大幅に違う値を示しています。
ここで、 safari のコンソールから window.innerWidth を取得してみると、

simulator_1_a.png

?!?!
なぜ?!?!?!

Chrome DevTools の結果(iPhone6)

chrome_1.png

こっちは想定どおりの値です。
コンソールから window.innerWidth を取得しても、

chrome_1_a.png

納得の結果です。

そもそも window.innerWidth とか document.documentElement.clientWidth って何の値なんだ

window.innerWidthMDN によると、

垂直スクロールバー(表示されている場合)を含む、ブラウザウィンドウの ビューポート (viewport) の幅を返します。

とのこと。

一方、document.documentElement は 同じく MDNによると、

document のルート要素 (HTML 文書の場合は <html> 要素) を返します。

であり、それの clientWidth ということは、同じく MDN によると、

clientWidth は element 内のピクセル単位の幅を返します。 paddingを含み、垂直スクロールバー(存在するならば)、border、marginを含みません。

なので、 document.documentElement.clientWidth<html> 要素の padding を含むが、垂直スクロールバー、border、 margin 含まない幅。

おおまかにいうと、垂直スクロールバーを含むか含まないかが違いそうです。
そのため、ブラウザによっては必ずしも全く同じではないことがわかります。
あと、document.documentElement.clientWidth でもいいか、と思ってたけど、厳密に viewport で判定したいときは window.innerWidth を使うべきだということもわかった。

ただし、今回スクロールバーは出てない文章量だし、980 と 375 っていう倍以上の差は一体何からうまれるのか…

色々試してみたら、一致するパターンがあった

色々と書き換えてみたところ、以下のように window.innerWidth の前に document.documentElement.clientWidth を取得してみたら、期待通りの値を取得できた。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <title>viewport test</title>
</head>
<body>
  <h1>viewport test</h1>
  <p id="text"></p>
  <script>
    window.addEventListener('load', function(){
      function printWidth(){
        document.getElementById('text').innerHTML = 
        'documentElement.clientWidth: '+document.documentElement.clientWidth+
        '<br>screen.width: '+screen.width+
        '<br>window.innerWidth: '+window.innerWidth;
      }
      printWidth();
    });
  </script>
</body>
</html>

iOS simulator の結果(iOS9.2 iPhone6)

simulator_2.png

Chrome DevTools の結果(iPhone6)

chrome_2.png

まとめ

iOS で window.innerWidth の取得値が期待通りにいかないときは、先に document.documentElement.clientWidth を取得するとうまくいくかもよ。

なぜなのか

わかりません。というかこの現象は必ず起こるものなのか。
どなたかご存知の方がいらっしゃいましたらコメントなどでお知らせ頂けますと助かります。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした