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; }
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); }
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); } }
I hope you take this code and make it even better
Discussion
👍. 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.
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.
This is cool. Took me a second to realize I had to open up the console to see the output.
Ya, its a relatively simple angular wrapper around ResizeObserver.