🤯 More to Media Queries than meets the eye 👁️ (in JavaScript example with Vue.js)

Adam Crockett 🌀 - Sep 27 '19 - - Dev Community

What is a media query for? You may know it as the thing to style all sorts of devices and print, determining sizes and more, but did you know that it's not just CSS which can query devices, you can use the match media API in JavaScript to unlock it's full potential.

So here is a little snippet post. It applies to all JavaScript but is especially useful in renderers.

You are required to set 2 css variables in your css:

:root {
    --tablet: 768px;
    --desktop: 1024px;
}
Enter fullscreen mode Exit fullscreen mode

This utility function is enough to provide limited tablet and desktop responsiveness, but it's not just styling... Oh no it's so much more. It's dumb but it works. I have a sexier angular class decorator if anyone is interested and missing the @ symbol.

Pros:

  • Query pixel ratio, orientation among other things, oh size, don't forget device size and screen size.
  • Elegant and simple
  • Tied to your real CSS meaning breakpoint s use single source of truth
  • Do crazzy stuff for performance such as excluding whole components from even rendering until query is met
  • Easy to understand intent
  • So very cool

Cons:

  • Needs CSS variables but easy to work around (maybe store env variables if transpiling?)
export function media(qs, cb) {
    if (cb) {
        const q = window.matchMedia(`screen and (${qs})`);
        const matches = () => {
            if (q.matches) {
                cb({matches: true});
            } else {
                cb({matches: false});
            }
        }
        matches();
        q.addListener(matches);
    }
}

export function isTablet(cb) {
  const device = `min-width: ${getComputedStyle(document.documentElement).getPropertyValue('--tablet')}`;
  media(device, cb);
}

export function isDesktop(cb) {
  const device = `min-width: ${getComputedStyle(document.documentElement).getPropertyValue('--desktop')}`;
  media(device, cb);
}
Enter fullscreen mode Exit fullscreen mode

Here is an example Vue (TSX) component using it, see created lifecycle to start with.

import "./SkillStack.scss";
import { isTablet } from "../utils/responsiveUi";

export default {
  name: 'SkillStack',
  data() {
    return {
      show: false
    }
  },
  render() {
    switch (this.show) {
      case true:
        return (
          <div class='sks'>
            <ul class='sks-Card_Stack'>
              <li class='sks-Card'>
                <h2>TECHNAME</h2>
                Proficientcy
              </li>
              <li class='sks-Card'>
                <h2>TECHNAME</h2>
                Proficientcy
              </li>
              <li class='sks-Card'>
                <h2>TECHNAME</h2>
                Proficientcy
              </li>
            </ul>
          </div>
        );
      case false:
        return null;
    }
  },
  methods: {
    toggleCardVisibility(e) {
      if (e && 'matches' in e) {
        this.show = e.matches;
      }
    }
  },
  created() {
    isTablet(this.toggleCardVisibility);
  }
}
Enter fullscreen mode Exit fullscreen mode

I hope you take this code and make it even better

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .