メディアクエリの解釈がMac Safariだけ違う


レスポンシブページを作る時に必要なブレイクポイント。
PCとSPでCSSだけでなくJSの処理を分けたいことは多々あります。

そんな時はこう書きますよね。

1.css
    @media screen and (max-width: 600px) {
      body{
        background-color: pink;
      }
    }
1.js
    window.onresize = function(){
      if(window.innerWidth > 600){
        ~~~~~~~ PC ~~~~~~~
      }else{
        ~~~~~~~ SP ~~~~~~~
      }
    }

そんな時、cssのブレイクポイントと、JSのブレイクポイントがズレたらお話しにならない。

メディアクエリは、スクロールバーを含めた幅で判定する

なのでウィンドウ幅の判定には、スクロール幅も含めた値を返す window.innerWidth を使う。$(window).width() はバーを含めない値を返すため、その分CSS側とズレてしまう。

上記を考慮して、
601px以上は白
600px以下はピンク
になるページが以下です。

DEMO

index.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>1</title>
    <style>
    * {
        margin: 0;
        padding: 0;
    }

    h1 {
        height: 2000px;
    }

    @media screen and (max-width: 600px) {
        body {
            background-color: pink;
        }
    }
    </style>
</head>

<body>
    <h1 id="h1"></h1>
    <script>
    // 変数
    var breakpoint = 600;
    var dom = document.getElementById("h1");

    // 関数
    var getW = function() {
        return window.innerWidth;
    }
    var setText = function(dom, text) {
            if (getW() > breakpoint) {
                dom.innerHTML = "白: " + text;
            } else {
                dom.innerHTML = "ピンク: " + text;
            }
        }
        // 実行
    setText(dom, getW());

    // バインド
    window.onresize = function() {
        setText(dom, getW());
    }
    </script>
</body>

</html>

ただ上記で、うまくいかないブラウザが一つありました。

Mac Safariです。

スクロールバーがない時は、他のブラウザと同じ挙動なのですが、
スクロールバーが出た瞬間に牙をむきました。

そう、こいつは、何故か

メディアクエリで、スクロールバーを含めない幅で判定する

という狂った挙動をとりました。
先ほどのデモだと

text → 白: 610 (JS側)
背景 → ピンク (CSS側)

というふうになり JS側とCSS側でズレてしまっています。

本当は1ブラウザの為にここまでやりたくなかったのですが、仕方ありません。
それが以下になります。

DEMO2

index2.html

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>2</title>
    <style>
    * {
        margin: 0;
        padding: 0;
    }

    h1 {
        height: 2000px;
    }

    @media screen and (max-width: 600px) {
        body {
            background-color: pink;
        }
    }
    </style>
</head>

<body>
    <h1 id="h1"></h1>
    <script>
    // 変数
    var breakpoint = 600;
    var dom = document.getElementById("h1");
    var isMacSafari = (function() { //mac safariの判定
        ua = window.navigator.userAgent.toLowerCase()
        if ((ua.indexOf('safari') !== -1) && (ua.indexOf('chrome') === -1) && (ua.indexOf('mac') !== -1)) {
            return true
        } else {
            return false
        }
    })();
    var scrollBar = isMacSafari ? window.innerWidth - document.body.clientWidth : 0; //バーの幅を出す

    // 関数
    var getW = function() {
        return window.innerWidth - scrollBar;
    }
    var setText = function(dom, text) {
        if (getW() > breakpoint) {
            dom.innerHTML = "白: " + text;
        } else {
            dom.innerHTML = "ピンク: " + text;
        }
    }

    // 実行
    setText(dom, getW());

    // バインド
    window.onresize = function() {
        setText(dom, getW());
    }
    </script>
</body>

</html>

ポイントとしては、
・MacSafariかどうかの判定
・その場合はスクロールバーの幅を出す
・MacSafariの時だけ、JSの処理の際、スクロールバー分だけ長さを引いて、CSSの方に合わせる

ユーザーエージェントって将来どうなるかわからないので、あまり使いたくないんです。。これ私のMacだけとかじゃないですよねw?(MacbookPro 2015モデル)

レスポンシブサイト作る上で必ずぶち当たると思うんですが、皆さんどうしているのか。
なにかもっとスマートなやり方があったら教えてくださいませ。