Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Media Queries in Emotion Styled Components

The Emotion docs tell us how to make reusable media queries that works in the css prop. This allows us to make the following queries in a css prop:

<div
  css={{
    color: 'green',
    [mq[0]]: {
      color: 'gray'
    },
    [mq[1]]: {
      color: 'hotpink'
    }
  }}
>

With mq[0] and mq[1] referring to the first two items in a breakpoints array. For example: const breakpoints = [576, 768, 992, 1200].

What's more, this article takes it one step further, by showing up how to get named reusable media queries by using a breakpoint object. It starts by making a similar function as per the emotion docs, but for objects:

const mq = n => {
  const bpArray = Object.keys(bp).map(key => [key, bp[key]]);

  const [result] = bpArray.reduce((acc, [name, size]) => {
    if (n === name) return [...acc, `@media (min-width: ${size}px)`];
    return acc;
  }, []);

  return result;
};

This then allows us to create a breakpoints object with named media queries:

// object
const breakpoints = {
  sm: 500,
  md: 768,
  lg: 992,
  xl: 1200
};


// query
${mq('sm')} { 
  color: gray;
}

So far, so good.

I would now like to do something similar in an emotion styled component. As such, I created an breakpoints object and the same function as mentioned in the above article.

I then tried to use the short hand media query in my emotion styled component -- like this:

import styled from '@emotion/styled'

const Container = styled.div`
  ${mq('sm')`max-width: 750px;`}
  ${mq('md')`max-width: 970px;`}
  ${mq('lg')`max-width: 1170px`}
`

But when I try this, it does not work. I get the following error message:

TypeError: Object(...) is not a function

Any idea why this is happening and what I can do to get it to work?

Thanks.

like image 575
Moshe Avatar asked Jan 01 '20 12:01

Moshe


People also ask

How do you write a media query in a styled component?

When writing media queries in styled-components I follow these three steps, and I can only recommend this approach. Define breakpoints based on application needs. Define devices using media query syntax. Apply the media query in the styled component.

Is emotion the same as styled-components?

The uses for Emotion are very different from those of styled-components. The main feature of this library is that the style composition is predictable for writing different CSS styles using JavaScript. This library supports both string and object styles.

Can we use multiple expressions in media query?

Each media feature expression must be surrounded by parentheses. Logical operators can be used to compose a complex media query: not , and , and only . You can also combine multiple media queries into a single rule by separating them with commas.

Are media queries logical expressions?

A media query is a logical expression that is either true or false. A media query is true if the media type of the media query matches the media type of the device where the user agent is running (as defined in the "Applies to" line), and all expressions in the media query are true.

How to use media queries in emotion?

Using media queries in emotion works just like using media queries in regular css except you don’t have to specify a selector inside the block, you can put your css directly in the css block. Some text! Media queries can be useful to create responsive apps but repeating them is annoying and can lead to inconsistencies.

How do media queries with styled components work?

Media queries with styled components work the same as in CSS! If you want a more involved example with defining different device sizes, continue below. We'll start from a simple webpage that is not responsive and improve it wth media queries! Checkout the code on Code Sandbox. So how to make it responsive using styled components?

How to make a responsive website using styled components?

So how to make it responsive using styled components? Define the devices for each breakpoint using the usual media query syntax Let's create one breakpoint for each size used in the Chrome Dev Tools: Then, based on the size, let's create a media query for each device supported.

Should media queries be defined in constants?

While defining media queries in constants is much easier than rewriting media queries each time, they’re still quite verbose since you usually want to change the same property at different breakpoints. facepaint makes this easier by allowing you to define what each css property should be at each media query as an array.


1 Answers

To clarify, there was mainly a minor syntax error in what the OP had posted (there should be no additional backticks in the interpolated string).

A full example of his code including type annotations would look like:

const breakpoints: { [index: string]: number } = {
  sm: 500,
  md: 768,
  lg: 992,
  xl: 1200,
};

const mq = Object.keys(breakpoints)
  .map((key) => [key, breakpoints[key]] as [string, number])
  .reduce((prev, [key, breakpoint]) => {
    prev[key] = `@media (min-width: ${breakpoint}px)`;
    return prev;
  }, {} as { [index: string]: string });

const Container = styled.div`
  ${mq["sm"]} {
    max-width: 750px;
  }
  ${mq["md"]} {
    max-width: 970px;
  }
  ${mq["lg"]} {
    max-width: 1170px;
  }
`;
like image 100
bluenote10 Avatar answered Sep 30 '22 16:09

bluenote10