question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add mediaQuery helper method to manage media queries

See original GitHub issue

Motivation: I really like the media query suggestions in tips-and-tricks.md, but I want something simpler to use.

In tips-and-tricks.md, we have:

// style-utils.js
import { css } from 'styled-components'

export const media = {
  handheld: (...args) => css`@media (max-width: 420px) { ${ css(...args) } }`,
  tablet: (...args) => css`@media (min-width: 421px) { ${ css(...args) } }`,
}
import { media } from '../style-utils';

const Box = styled.div`
  font-size: 16px;
  ${media.handheld`
    font-size: 14px;
  `}
`;

The best part of this tip is that it allows the developer to pick whatever name they want when defining the static object that holds all the media query helpers (e.g. media, respondTo, atMedia, …). And, since it is a static object, IDEs will offer auto-complete suggestions when you type the name of the object. I.e. typing media. in your IDE will offer media.handheld, media.tablet and all other media queries defined in your object.

The only problem with the tip is that there is a lot of boilerplate. (...args) => css`@media (query goes here) { ${ css(...args) } }`, and it is not possible (for mere mortals) to memorize that.

At first I wrote a simple helper function that setup the boilerplate and could be used like this:

const media = {
  tablet: mediaHelper('(min-width: 420px)'),
}

But I realized that it would be nice if we could use a tagged template literal for the media query string too. Like this:

const media = {
  tablet: mediaQuery`(min-width: 420px)`,
}

This had the bonus effect that it removed one set of parenthesis and made the code easier to read.

NOTE: if you are wondering why the mediaQuery method can’t handle the parenthesis around the query string so that you could just type this: mediaQuery`min-width: 420px`, consider the following query: @media tv, (max-width: 520px) {}, which is not wrapped entirely by a single set of parenthesis.

After a bit of playing with styled-component’s css() method, I came up with this:

const mediaQuery = (...query) => (...rules) => css`
  @media ${css(...query)} {
    ${css(...rules)}
  }
`

I love how this function looks. Thank you, css() method! You rock.

Now that we have that method, we can do stuff like this:

// style-utils.js
import { mediaQuery } from 'styled-components' // assuming this feature is added!

const sizes = {
  tablet: 768,
  desktop: 992,
  giant: 1170,
}

// use em in breakpoints to work properly cross-browser and support users
// changing their browsers font-size: https://zellwk.com/blog/media-query-units/
export const media = {
  handheld:   mediaQuery`(max-width: ${(sizes.tablet - 1) / 16}em)`,
  tablet:     mediaQuery`(min-width: ${sizes.tablet / 16}em)`,
  tabletOnly: mediaQuery`(min-width: ${sizes.tablet / 16}em) and (max-width: ${(sizes.desktop - 1) / 16}em)`,
  desktop:    mediaQuery`(min-width: ${sizes.desktop / 16}em)`,
  giant:      mediaQuery`(min-width: ${sizes.giant / 16}em)`,
  minWidth:   (pxValue) => mediaQuery`(min-width: ${pxValue / 16}em)`,
  print:      mediaQuery`print`,
}
import styled, { css } from 'styled-components';
import { media } from '../style-utils';

const Box = styled.div`
  font-size: 16px;

  ${media.handheld`
    font-size: 14px;
  `}

  /* Create a media query with a custom width not needed in other components. */
  ${media.minWidth(500)`
    border-width: 2px;
  `}

  /* tagged functions created with mediaQuery can be nested with other
     interpolations using styled-component's tagged function, css(). */
  ${({ wide }) => wide && css`
    width: 100%;

    ${media.tablet`
      width: 80%;
      margin: 0 auto;
    `}
  `}
`;

I thought about making this a separate module ( https://github.com/JohnAlbin/styled-media-queries ), but it will be a lot more work to do that then it will to make a PR. So I’m making a PR instead. 😃 Plus, the css() method is doing all the work.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:9
  • Comments:8 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
oolothcommented, Oct 20, 2017

@philpl Apologies! That went a little over my head…

To help me understand, on May 22 you gave an example of this as a future-proof media query helper:

media.tablet(css`
  width: 80%;
  margin: 0 auto;
`)

Can you please clarify what future-proof function should be used to generate media.tablet for that helper? I’d like to use a media query helper that works with the babel plugin (if that’s possible).

(Thank you!)

1reaction
kittencommented, May 22, 2017

@JohnAlbin So in the babel plugin we introduced experimental preprocessing support in v2.

Preprocessing effectively runs stylis during build time, flattening CSS, and turning it into an efficient string[][] structure. It does so by processing all usages of css, keyframes, injectGlobal, and of course styled.... It won’t be able to preprocess any usages of them that are purely dynamic. This means that a helper like this won’t work with the babel plugin.

This is not an issue since it’s experimental right now, and not recommended to be used in production. However, the big idea is to make it stable and more tightly integrated in v3 of SC. This means that helpers like this will unexpectedly break once we do recommend the babel plugin to be used.

A future proof helper thus might look like this:

media.tablet(css`
  width: 80%;
  margin: 0 auto;
`)

I do want to stress that your helper is perfectly fine right now and won’t break in v2. It will even work in v3 of course. But it will likely never work with the babel plugin. 😉 I hope that answers your question sufficiently

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using media queries - CSS: Cascading Style Sheets | MDN
A media query is composed of an optional media type and any number of media feature expressions, which may optionally be combined in...
Read more >
Approaches to Media Queries in Sass - CSS-Tricks
First of all, I want my code to be easy to read to the point that anyone understands instantly that a media query...
Read more >
Using media queries and CSS functions to create a ...
Using flex box and media queries – the menu · Select the “ul” element from the Tree panel. · Open the Style panel...
Read more >
How To Use Media Queries in React - Upmostly
Media queries are used in responsive design. They are used to apply different CSS rules to different types of devices, most commonly screen...
Read more >
Media queries in React for responsive design - Material UI - MUI
You should provide a media query to the first argument of the hook. The media query string can be any valid CSS media...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found