styled components media queries

Styled Components Media Queries - A Better Approach to Responsive Styling

Author Profile
Abdul Basit OnLinkedIn

Never write media queries hard-coded in styled components; always create variables for them.

Let me explain why…

CSS clamp and calc functions help a lot in making sites responsive without media queries. However, there are still cases when we need media queries. For example, adjusting the layout for different screen sizes, showing or hiding elements at a particular size, or adapting typography for various devices.

In previous issues of our styled components article series, we have talked about how to structure styled components in a React app, the ways to write reusable styles, and in the last article, we learned how to write reusable Flex components for faster development.

We have covered many things. Today, we are going to see how to write media queries in styled components for a production application.

Let's learn it step by step.

Let's start with an example. Imagine we have three cards displayed in a row, but we want them to stack in a column layout if the screen size is 600px or less.

styled components reusable media queries

Here's how you could write the media query without optimizing it so we can see the difference.

const BlogCardsContainer = styled.div`
display: flex;
justify-content: space-between;
@media (max-width: 600px) {
flex-direction: column;
}
`

This approach works well; however, there are several problems with hard-coding media queries:

  1. We have to remember all the breakpoints.
  2. If you need to make changes to the UI, such as applying smaller screen changes (600px) to tablet screens (768px), you would have to manually locate and update every instance of the media query in the code.
  3. The third problem is that it's not user-friendly; every time we have to repeat @media (max-width:600px).

To address these problems, a better approach is to create a separate file called breakpoints.ts (assuming you are using TypeScript with styled components) in the styles folder for media queries. In this file, you can define all the breakpoints as an object.

interface Size {
xs: string
sm: string
md: string
lg: string
xl: string
xxl: string
}
const size: Size = {
xs: '400px', // for small screen mobile
sm: '600px', // for mobile screen
md: '900px', // for tablets
lg: '1280px', // for laptops
xl: '1440px', // for desktop / monitors
xxl: '1920px', // for big screens
}
export const device = {
xs: `(max-width: ${size.xs})`,
sm: `(max-width: ${size.sm})`,
md: `(max-width: ${size.md})`,
lg: `(max-width: ${size.lg})`,
xl: `(max-width: ${size.xl})`,
xxl: `(max-width: ${size.xxl})`,
}

With this setup, you can now write media queries in a more optimized way:

const BlogCardsContainer = styled.div`
display: flex;
justify-content: space-between;
@media ${device.sm} {
flex-direction: column;
}
`

By using the device object and accessing the appropriate property (sm in this case), we have solved the three problems mentioned earlier. It's much easier to remember and update breakpoints since they are defined in a central file, and the code becomes more readable and user-friendly.

Isn't it awesome?

Now the question is, can we further improve it?

Yes we can, the repetition of @media by optimizing it using the css function from styled-components. Here's an example of how you can achieve this:

But it personal preference, if you like this approach you can implement it.

import { css } from 'styled-components'
const device = {
xs: '400px',
sm: '600px',
md: '900px',
lg: '1280px',
xl: '1440px',
xxl: '1920px',
}
const media = {
xs: (...args) => css`
@media (max-width: ${device.xs}) {
${css(...args)};
}
`,
sm: (...args) => css`
@media (max-width: ${device.sm}) {
${css(...args)};
}
`,
md: (...args) => css`
@media (max-width: ${device.md}) {
${css(...args)};
}
`,
lg: (...args) => css`
@media (max-width: ${device.lg}) {
${css(...args)};
}
`,
xl: (...args) => css`
@media (max-width: ${device.xl}) {
${css(...args)};
}
`,
xxl: (...args) => css`
@media (max-width: ${device.xxl}) {
${css(...args)};
}
`,
}

Now you can use the media object to write media queries more concisely:

const BlogCardsContainer = styled.div`
display: flex;
justify-content: space-between;
${media.sm`
flex-direction: column;
`}
`

The same pattern can also be used with SCSS by making syntax modifications.

I hope you learned something useful in this article.

If you want to learn

If you want me to write an article on how I make font-size, margins and paddings responsive using CSS clamp and calc functions without writing media queries, let me know via email at [email protected], LinkedIn, or Twitter.