ウィンドウサイズの取得・判定をしてみよう

レスポンシブ対応のときに、ウィンドウサイズによって何かしらの処理を行うことがあります。

CSSではメディアクエリを使って、ウィンドウサイズによってスタイルを指定することができます。

p {
  font-size: 18px;
}

@media screen and (max-width: 768px) {
  p {
    font-size: 16px;
  }
}

@media screen and (max-width: 375px) {
  p {
    font-size: 13px;
  }
}

しかし、JavaScriptではwindow.innerWidthやjQueryのwidth()でウィンドウ幅を取得して、判定しなければならず、CSSと違ってウィンドウサイズが変更されたらそれを検知して実行する必要があります。

これがまた一手間で、ブラウザによっては挙動が違ったり、検知に負荷がかかってしまったり…。なかなか苦労させられます。

その対応策として、比較的新しい手法でmatchMediaメソッド、MediaQueryListオブジェクトを使うというものありますが、まずは現状よく使われている手法を解説します。

目次

ウィンドウサイズの取得・判定

JavaScriptでウィンドウサイズ(ここではウィンドウの幅)を取得するには、window.innerWidthやjQueryのwidth()を使います。

JavaScriptのwindow.innerWidthを使った例

// JavaScript
var windowSize = window.innerWidth;

if (windowSize < 376) {
  console.log('Small!');
} else if (windowSize < 768) {
  console.log('Medium!');
} else {
  console.log('Large!');
}

jQueryのwidth()を使った例

// jQuery
var windowSize = $(window).width();

if (windowSize < 376) {
  console.log('Small!');
} else if (windowSize < 768) {
  console.log('Medium!');
} else {
  console.log('Large!');
}

なお、jQueryのwidth()メソッドでは、スクロールバーを含まないウィンドウサイズを取得するので、CSSのメディアクエリの値とは一致しませんので、そこを調整する必要があります。

ウィンドウのサイズ変更を検知して処理を実行

ウィンドウサイズを取得して判定することはできましたが、このままではページが読み込まれたときに実行されてそれで終了となります。
つまり、ウィンドウの幅を狭くしたり、スマートフォンやタブレットを縦から横に向きを変えるなど、なんらかの変更があった場合、それに対応できません。

ウィンドウサイズが変更を検知するには、window.onresizeやjQueryのresizeを使います。

JavaScriptのwindow.onresizeを使った例

window.onresize = function () {
  var windowSize = window.innerWidth;

  if (windowSize < 376) {
    console.log('Small!');
  } else if (windowSize < 768) {
    console.log('Medium!');
  } else {
    console.log('Large!');
  }
};

jQueryのresizeを使った例

$(window).on('resize', function(){
  var windowSize = $(window).width();

  if (windowSize < 376) {
    console.log('Small!');
  } else if (windowSize < 768) {
    console.log('Medium!');
  } else {
    console.log('Large!');
  }
});

resizeイベントの問題点

前述のコードを実行すれば、ウィンドウサイズが変更されたときにそのウィンドウ幅を取得して、条件にあったメッセージがコンソールに表示されるようになります。

ただ、このやり方にはちょっとした問題があります。
それは、ウィンドウサイズが変更されている間、ずっと処理が実行されることです。

試しに、以下のコードをブラウザのデベロッパーツール(開発ツール)のコンソールで実行してみてください。
すごい勢いでコンソールに「Resize!」というメッセージが表示されます。

window.onresize = function () {
  console.log('Resize!');
};
ちょっと動かしただけで、132個のメッセージが…。

このコードは単純にメッセージを出力するだけですが、これが複雑な処理を実行する物だとブラウザに負荷がかかってしまいます。
それに対処する方法として、タイマーを使って負荷軽減というやり方があります。

setTimeoutメソッドで負荷軽減

JavaScriptにはsetTimeoutというメソッドがあります。

これは指定した時間(ミリ秒)が経過すると指定した関数を実行するメソッドです。

以下のコードをブラウザのデベロッパーツール(開発ツール)のコンソールで実行してみてください。
1秒後に「Finish!」と出力されます。

window.setTimeout(function(){
  console.log('Finish!') }, 1000
);

これを使ってresizeイベントの負荷軽減をします。
以下が、その例です。

var timer = '';
window.onresize = function () {
  if (timer) {
    clearTimeout(timer);
  }
  timer = setTimeout(function(){
    console.log('Resize!');
  }, 200);
};

ソースコードの解説

まず、setTimeoutメソッドの返り値を格納する変数timerを定義します。

STEP
変数timerを定義
var timer = '';

setTimeoutメソッドの返り値を格納する変数timerを定義します。

この変数timerに入った返り値が、実行中のタイマーを識別するIDとなります。

STEP
onresizeイベントに関数を設定
window.onresize = function () {};

window.onresizeに関数を設定して、resizeイベントが発行されたときに処理が実行するようにします。

STEP
タイマーが実行中か判定
if (timer) {
}

すでに書きましたとおり、ウィンドウを動かしている間、断続的にresizeイベントが発行されます。
そのため、タイマーが実行している間にreizeイベントが発行されると新しいタイマーが重ねて設定されてしまいます。

それを防ぐため、変数timerに返り値が格納されているかどうかを、if (timer) {}で判定します。

STEP
タイマーが実行されていれば、実行中のタイマーを解除
clearTimeout(timer);

変数timerに値が格納されていればタイマーが実行中なので、clearTimeoutに実行中のタイマーを識別する値が入った変数timer渡し、タイマーを停止(クリア)します。

STEP
タイマーを設定して、200ミリ秒後に処理を実行させる
timer = setTimeout(function(){
  console.log('Resize!');
}, 200);

setTiemoutメソッドを定義します。

200ミリ秒後にメッセージを出力する処理を実行するように、引数を設定します。また、返り値を変数timerへ渡します。

これでウィンドウサイズを変更している間(resizeイベントが発行され続けている間)は、タイマーが停止・再度設定が繰り返されて処理が実行されなくなります。

そして、ウィンドウサイズの変更が終わったとき(最後のresizeイベントが発行されたとき)に、タイマーが実行されて、200ミリ秒後に処理が実行されます。

実行例

それでは、コードをブラウザのデベロッパーツール(開発ツール)のコンソールで実行してみましょう。

全然違います

ウィンドウサイズを変更している間はメッセージが出力されず、変更後に出力されていますね。

ウィンドウサイズに合わせて処理を実行する

これまでのコードを元に、ウィンドウサイズに合わせて処理を実行するコードを書いてみましょう。

JavaScriptの場合

var timer = '';
window.onresize = function () {
  if (timer) {
    clearTimeout(timer);
  }
  timer = setTimeout(function(){
    var windowSize = window.innerWidth;

    if (windowSize < 376) {
      console.log('Small!');
    } else if (windowSize < 768) {
      console.log('Medium!');
    } else {
      console.log('Large!');
    }
  }, 200);
};

jQueryの場合

var timer = '';
$(window).on('resize', function(){
  if (timer) {
    clearTimeout(timer);
  }
  timer = setTimeout(function(){
    var windowSize = $(window).width();
  
    if (windowSize < 376) {
      console.log('Small!');
    } else if (windowSize < 768) {
      console.log('Medium!');
    } else {
      console.log('Large!');
    }
  }, 200);
});

実際に動かしてみると、こんな感じで指定したウィンドウサイズに合わせてメッセージが出力されます。

ウィンドウサイズに合わせてメッセージが出力されています

まとめ

JavaScriptでウィンドウサイズによって処理を変えることは、なかなか手間のかかることというのが分かるのではないでしょうか。
CSSのメディアクエリは便利ですね。ウィンドウサイズは後々変更されてもすぐに反映されますから…。

とは言っても、Webの技術は日々進歩していますから、最近ではもっと簡単に効率良く判定・処理実行することができるようになってきています。
最初に少し触れたmatchMediaメソッド、MediaQueryListオブジェクトもその一つです。

きっと、もっと簡単なメソッドで設定できるようになって、

manoのアイコン画像mano

あのときは苦労したものじゃよ。ホッホッホ

と、お茶を飲みながらのたまうお爺ちゃんのように、若手に語れる日が来ることでしょう。たぶん。

この記事を書いた人

Webコーダーとして日々研鑽しています。

目次
閉じる