# Media Queries

When it comes to building responsive interfaces, the *media query* is the primary tool in our toolbox.

```xml
<style>
  .signup-button {
    color: deeppink;
    font-size: 1rem;
  }
  
  @media (max-width: 400px) {
    .signup-button {
      font-size: 2rem;
    }
  }
</style>
```

The `@media` keyword is known as an "at-rule". at-rules are a special kind of CSS statement that changes behaviour. There are a handful of at-rules that all do different things; another example is `@keyframes`, which allows you to define an animation sequence.

Media queries selectively apply rules based on one or more conditions. In this case, we're saying that the `.signup-button` selector should adopt an additional declaration when the viewport is 400px wide or less.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">It's also important to note that&nbsp;<strong>media queries don't affect specificity</strong>. The only reason that&nbsp;<code>font-size: 2rem</code>&nbsp;beats&nbsp;<code>font-size: 1rem</code>&nbsp;is because it comes later.</div>
</div>

With regular media queries, declarations are grouped by viewport size:

```css
/* All tablet styles */
@media (min-width: 550px) {
  .wrapper {
    padding: 16px;
    border: 3px solid;
  }
  h2.title {
    font-size: 2.5rem;
  }
}
```

With styled-components, all of the declarations for an element are in the same spot.

Fortunately, **this "nested media queries" thing is not unique to styled-components.** CSS preprocessors like Sass also support nested media queries. I suggest using this pattern if your tool allows for it.

```javascript
// All Wrapper styles
const Wrapper = styled.div`
  padding: 8px;
  border: 2px solid;

  @media (min-width: 550px) {
    padding: 16px;
    border: 3px solid;
  }
`;
```

This pattern makes it way easier to reason about which styles apply to which elements. Everything you need to know, in 1 place.

## Mobile-first vs desktop-first

There are two distinct ways we can write the media query we saw above:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394794655/e5f1e388-f097-4caa-a563-2091f7d6a5f7.png align="center")

The first snippet is known as **desktop-first**, since our default styles (the ones not inside `@media`) target desktop devices, and then we specify overrides for mobile devices. By contrast, the second snippet is **mobile-first**, since the main styles are for mobile devices (400px or smaller).

> When starting a new project, you'll need to pick whether you take a desktop-first or a mobile-first approach.
> 
> If the project will be viewed primarily by folks on mobile devices, it makes sense to go mobile-first.
> 
> Another factor to consider: are you *designing* the project, in addition to implementing it? If so, it can be helpful to think in mobile-first terms, because **it's easier to add than to take away**.
> 
> Ultimately, though, the most important thing is to **be consistent with the approach.** If you decide to build mobile-first, you should almost always use `min-width` media queries. It can be very confusing if you mix `min-width` and `max-width` media queries.

### Mixing patterns

Here's a pattern I *try* to avoid:

```xml
<style>
  @media (max-width: 600px) {
    .desktop-button {
      display: none;
    }
  }

  @media (min-width: 601px) {
    .mobile-button {
      display: none;
    }
  }
</style>
```

One minor problem is that fractional viewport widths (eg. 600.5px) *are* possible, according to the specification. I've seen this firsthand when the page is embedded in an iframe, but there may be other situations that lead to non-integer viewport widths.

But here's the real reason I try not to do this: It complicates the mental model.

I believe that our applications should be either mobile-first or desktop-first. If we consistently use a single set of media queries, it'll help us quickly scan chunks of CSS to understand the structure.

How would we solve this problem without mixing queries? Here's how I'd structure this (mobile-first approach):

```css
.desktop-button {
  display: none;
}

@media (min-width: 601px) {
  .desktop-button {
    display: revert;
  }

  .mobile-button {
    display: none;
  }
}
```

`revert` is a special keyword that restores the property to its default value. It's a way of undoing the `display: none` set outside the media query.

Structuring things this way is more verbose, but I think it's worth it.

That said, there are exceptions. Sometimes, it's just too much trouble to structure things this way.

For example, if we have a completely different layout that only exists on tablet, it can be nice to wrap it in a "tablet only" media query:

```css
@media (min-width: 500px) and (max-width: 1023px) {
  .wrapper {
    display: flex;
    flex-direction: row;
    gap: 32px;
    align-items: flex-start;
    justify-content: center;
  }
}
```

It *is* possible to rewrite this to only use `min-width`, but it would ultimately make the CSS harder to understand.

## Media queries and units

When creating `min-width` / `max-width` media queries, should we use pixels? Or maybe another unit, like rems?

```css
/* Should we do this: */
@media (min-width: 800px) {
  }

/* …Or this: */
@media (min-width: 50rem) {
}
```

**What's the difference?** As we learned in [Module 1](https://courses.joshwcomeau.com/css-for-js/00-recap/06-units)[, the `re`](https://courses.joshwcomeau.com/css-for-js/00-recap/06-units)`m` unit is equal to 16px by default, but can be redefined, either by the developer *or by the end user.*

Suppose the user has poor vision, and they want to boost the size of text. They go into their browser settings, and crank up the baseline font size to 32px. Now, each `rem` unit is equal to 32px instead of 16px.

And so here's the question: **Should our media queries be affected by the user's chosen baseline font size?**

For a long time, I thought the answer was “no”, and I used pixels for all media queries. But over the past few months, I've reconsidered this position.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728481268207/78e99518-9327-4f69-a13f-27bfb16bbafe.png align="center")

With pixel-based media queries, we stick with the desktop layout no matter what the user does with their default font size. When cranked to 32px, it means we wind up with a really cramped layout: the sidebar expands and fills half of the screen (since it uses a rem-based width).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728481326454/ebf477df-b2fd-4748-a6bc-a67de760a1ed.png align="center")

When we use rem-based media queries, we flip to the *mobile* view (even though they're using a desktop-sized window). The large text has more room to breathe, and it's generally just a much better experience.

For this reason, **I recommend using** `rem` media queries in most situations.

You can also use `em` instead of `rem`; the two units function exactly the same way, when it comes to media queries.

For more information, check out my blog post, [“The Surprising Truth about Pixels and Accessibility”](https://www.joshwcomeau.com/css/surprising-truth-about-pixels-and-accessibility/#media-queries).
