レスポンシブ対応のときに、ウィンドウサイズによって何かしらの処理を行うことがあります。
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!');
};
このコードは単純にメッセージを出力するだけですが、これが複雑な処理を実行する物だとブラウザに負荷がかかってしまいます。
それに対処する方法として、タイマーを使って負荷軽減というやり方があります。
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
を定義します。
timer
を定義var timer = '';
setTimeout
メソッドの返り値を格納する変数timer
を定義します。
この変数timerに入った返り値が、実行中のタイマーを識別するIDとなります。
onresize
イベントに関数を設定window.onresize = function () {};
window.onresize
に関数を設定して、resize
イベントが発行されたときに処理が実行するようにします。
if (timer) {
}
すでに書きましたとおり、ウィンドウを動かしている間、断続的にresizeイベントが発行されます。
そのため、タイマーが実行している間にreize
イベントが発行されると新しいタイマーが重ねて設定されてしまいます。
それを防ぐため、変数timer
に返り値が格納されているかどうかを、if (timer) {}
で判定します。
clearTimeout(timer);
変数timer
に値が格納されていればタイマーが実行中なので、clearTimeout
に実行中のタイマーを識別する値が入った変数timer渡し、タイマーを停止(クリア)します。
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
オブジェクトもその一つです。
きっと、もっと簡単なメソッドで設定できるようになって、
あのときは苦労したものじゃよ。ホッホッホ
と、お茶を飲みながらのたまうお爺ちゃんのように、若手に語れる日が来ることでしょう。たぶん。