CSS in JS でメリットも。 window.matchMedia を使う

ブレイクポイントで処理分けたい

ブレイクポイントで JavaScript の処理を変更するには、window の幅を resize イベントで監視する方法が使われてきました。

しかし、resize の度にイベントが走りパフォーマンスに影響を与えるのでイベントを間引く処理を書いたりします。
ライブラリでは lodash の throttle や debounce が用意されていますね。

今回ご紹介する matchMedia は、値を定期的にポーリングするのではなく、メディアクエリの状態が変更された時に検知できるため効率的です。

window.matchMedia とは

メディアクエリの状態が変更されたことを検知できます。
CSS のメディアクエリによるスタイル変更のように、JavaScript でブレイクポイントによって処理を分けることができます。

対応ブラウザ

IE10 から対応しています。

can i use - matchMedia

コチラ

実装例

ソースコード

MDN の実装例を見てみましょう。

ブラウザ確認

実装の Demo が確認できます。

ソースコードを見ると、 matchMedia メソッドの引数には、CSS のメディアクエリと同じ記述が入ります。

var mql = window.matchMedia('(max-width: 600px)');

これは、CSS in JS の環境において、 変数として再利用できるメリット があり、ブレイクポイントの記述が一元管理できます。
Vue.js で実装してみましたのでご確認ください。

Vue.js での利用例

<style lang="postcss" module>
@value breakpoint: (max-width: 600px);

.hello {
  background: #ccc;
}

@media breakpoint {
  .hello {
    background: #f00;
  }
}
</style>

<template>
  <div :class="$style.hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data() {
    return {
      msg: '',
    };
  },
  mounted() {
    this.$nextTick(() => {
      const mql = window.matchMedia(this.$style.breakpoint);
      this.func(mql);
      mql.addListener(this.func);
    });
  },
  methods: {
    func(mql) {
      if (mql.matches) {
        this.msg = 'ウィンドウが 600px 以下です';
      } else {
        this.msg = 'ウィンドウが 601px 以上です';
      }
    },
  },
}
</script>

コードを github.com に up しています。
npm install, npm run serve でブラウザ確認できます。

まとめ

window.matchMedia は、従来の resize イベントで window の幅を監視するより負荷が少なく、少ないコード量でブレイクポイントごとの処理を分岐できます。

さらに、CSS in JS の環境では、メディアクエリの文字列を CSS と JS で共通化できるようになりました。
対応ブラウザも多いため、積極的に使っていける機能だと思います。

以上