LoginSignup
6

More than 5 years have passed since last update.

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

Posted at

レスポンシブページを作る時に必要なブレイクポイント。
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モデル)

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

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
6