DEV Community

Adam Crockett 🌀
Adam Crockett 🌀

Posted on • Edited on

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

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

Top comments (3)

Collapse
 
johncarroll profile image
John Carroll • Edited

👍. Similarly, for situations where you wish to style an element based on it's display size (or the display size of the element's container)--rather than the browser's screen size--I made an Angular library to help out: dev.to/johncarroll/angular-size-ob.... Useful when a container's size is dynamic but not dependent on the window's size.

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀 • Edited

Hey John, nice work! Looks like ResizeObserver? As an asside, I mentioned a decorator in the post above, I feel like I should show you as you are in with the Angular camp.

Note that the code in this decorator could be improved by the code in this post because adding listeners to window is not the correct way, but you get the idea, it looks cool.

Collapse
 
johncarroll profile image
John Carroll

This is cool. Took me a second to realize I had to open up the console to see the output.

Looks like ResizeObserver

Ya, its a relatively simple angular wrapper around ResizeObserver.