スマホの時だけJavaScriptを動かす方法

この記事の前提条件

対象: JavaScript(全モダンブラウザ対応)
難易度: ★★☆
所要時間: 約5分

「スマホの時だけハンバーガーメニューの開閉処理を動かしたい」「PCではホバーで、スマホではタップで開閉したい」…画面サイズによってJavaScriptの挙動を切り替えたい場面はよくあります。CSSの@mediaのように、JavaScript側でも画面幅を判定できます。

window.matchMedia()で判定する

CSSと同じメディアクエリの条件式を、JavaScript側からも判定できるwindow.matchMedia()を使います。

const isMobile = window.matchMedia('(max-width: 768px)').matches;

if (isMobile) {
  // スマホの時だけ実行したい処理
}

.matchesは、条件に一致していればtrue、していなければfalseを返します。CSSのブレイクポイントと同じ数値を指定しておけば、CSSとJavaScriptの切り替わりタイミングをぴったり揃えられます。

⚠️ ページ読み込み時の1回だけの判定になる

上記のコードは、ページを読み込んだ瞬間の画面幅で1回だけ判定します。PCでウィンドウ幅を手動で狭めた場合など、途中でスマホサイズをまたいでも、この判定結果は自動的には更新されません。ウィンドウのリサイズにもリアルタイムで追従させたい場合は、次の方法を使います。

リサイズにも追従させたい場合: addEventListener

matchMedia()の戻り値に対してaddEventListener('change', ...)を登録すると、画面幅がそのブレイクポイントをまたいだ瞬間に処理を実行できます。

const mediaQuery = window.matchMedia('(max-width: 768px)');

function handleChange(e) {
  if (e.matches) {
    console.log('スマホサイズに切り替わりました');
  } else {
    console.log('PCサイズに切り替わりました');
  }
}

mediaQuery.addEventListener('change', handleChange);
handleChange(mediaQuery); // 初回読み込み時にも実行しておく

実務での注意点: window幅ではなくmatchMediaを使う理由

window.innerWidthの数値を直接比較する方法も見かけますが、CSSのブレイクポイントと条件式が別々の場所に分かれてしまい、片方だけ修正して不一致になる事故が起きやすいです。matchMedia()ならCSSと全く同じ書式の条件式を使えるので、CSS側のブレイクポイントを変更した時に、JavaScript側の条件も一緒に見直しやすくなります。

まとめ

  • window.matchMedia('(max-width: 768px)').matchesで画面幅を判定できる
  • そのままだと読み込み時の1回だけの判定なので、リサイズに追従させるにはaddEventListener('change', ...)を使う
  • CSSと同じ条件式が使えるため、ブレイクポイントの管理がしやすくなる