Posted at

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

More than 1 year has passed since last update.

レスポンシブページを作る時に必要なブレイクポイント。

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モデル)

レスポンシブサイト作る上で必ずぶち当たると思うんですが、皆さんどうしているのか。

なにかもっとスマートなやり方があったら教えてくださいませ。