Responsive-layout gotcha: watch out for older Safari versions!
If you’re using media queries in Javascript to do responsive layout, you might be adding listeners to mediaQueryList
, a pretty common technique:
const mediaQueryList = window.matchMedia(mediaQuery);
const propagate = (e: MediaQueryListEvent) => {
return e.matches ? handler(true) : handler(false);
};
mediaQueryList.addEventListener('change', propagate);
However, beware! We recently encountered an ugly problem where older versions of Safari and mobile Safari (12 and before) were throwing an error like property 'addEventListener' does not exist on type 'MediaQueryList'
— no joke, this was actually crashing the site!
The problem is that Safari is special — they didn’t upgrade mediaQueryList
to use addEventListener
as when most folks did. The MDN docs say that although it’s deprecated it’s also:
“… retained for backwards compatibility purposes. Older browsers should use
addListener
instead ofaddEventListener
sinceMediaQueryList
only inherits fromEventTarget
in newer browsers.”
So we have one of those unfortunate cases where we need to handle past and future cases. Here’s an easy way to do that:
mediaQueryList.hasOwnProperty('addEventListener')
? mediaQueryList.addEventListener('change', propagate)
: mediaQueryList.addListener(propagate);// later when you want to clean up
mediaQueryList.hasOwnProperty('removeEventListener')
? mediaQueryList.removeEventListener('change', propagate)
: mediaQueryList.removeListener(propagate);
That’s all, come see us at Y’all!
TL;DR
To be sure we never miss this, we’ve built a useMedia
React hook that lets you pass in a media-query string and then handles subscribe/cleanup for you — and because we do SSG/SSR in Gatsby and Next.js, it only does this when rendering on the client. Then to ensure we have a single source of truth for our breakpoints, we :export
them as fully formatted media queries from sass, like mq_mobile: unquote(‘screen and (max-width: #{$bp-mobile})’)
.
It’s a pretty tight system — if you’re interested let me know and I’ll share it sometime! ⭐️