admin管理员组

文章数量:1302871

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 ponent. 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 ponent -- 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.

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 ponent. 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 ponent -- 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.

Share Improve this question asked Jan 1, 2020 at 12:00 MosheMoshe 7,00721 gold badges76 silver badges137 bronze badges 2
  • 2 ${mq('sm')} {max-width: 750px;}? – Agney Commented Jan 1, 2020 at 12:16
  • Thanks -- that did it. – Moshe Commented Jan 1, 2020 at 17:56
Add a ment  | 

2 Answers 2

Reset to default 6

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;
  }
`;

The @bluenote10 answer is correct. Here's a boosted method if you want to add auto-pletion with your IDE in your css definition.

export const BREAKPOINTS = {
  xs: 420,
  sm: 576,
  md: 768,
  lg: 900,
  xl: 1200,
  xxl: 1536
};

type Mq = keyof typeof BREAKPOINTS;
export const mql = Object.keys(BREAKPOINTS)
  .map((key) => [key, BREAKPOINTS[key as Mq]] as [Mq, number])
  .reduce((prev, [key, breakpoint]) => {
    prev[key] = `@media (min-width: ${breakpoint}px)`;
    return prev;
  }, {} as Record<Mq, string>);

本文标签: javascriptMedia Queries in Emotion Styled ComponentsStack Overflow