# Range Syntax em Media Queries

> A sintaxe de intervalos (Range Syntax) em media queries é mais legível, fácil de depurar e bem suportada. Saiba por que vale substituir min-width e max-width.

URL: https://dpw.dev/css/css-range-syntax-media-queries/  
Publicado em: 2026-05-11  
Categoria: css  
Tags: web-design-responsivo  
Autor: Tárcio Zemel

Media queries são a espinha dorsal do <a href="/tag/web-design-responsivo/" target="_blank">web design responsivo</a>. São elas que controlam como um layout deve se ajustar conforme o tamanho da viewport. O problema é que a sintaxe com `min-width` e `max-width` pode confundir e, em alguns casos, gerar bugs de layout que consomem tempo para serem identificados.

Felizmente, agora temos uma alternativa mais legível e mais fácil de usar e depurar: a **Range Syntax** (ou Sintaxe de Intervalos).

> Artigo baseado em [Media Queries Range Syntax](https://ishadeed.com/article/range-syntax/).

## O problema com media queries

Imagine um padrão clássico de navegação: no mobile, apenas o logo e o botão de menu (toggle) aparecem; em telas maiores, a navegação fica visível e o toggle é escondido.

A seguir, as media queries usadas para isso:

```css
/* Esconde a navegação em tamanhos pequenos */
.nav {
  @media (max-width: 300px) {
    display: none;
  }
}

/* Esconde o toggle em tamanhos grandes */
.toggle {
  @media (min-width: 300px) {
    display: none;
  }
}
```

O problema acontece quando as duas media queries se encontram no mesmo valor de breakpoint (`300px`): _ambos elementos serão escondidos ao mesmo tempo_.

Vale lembrar:

- `max-width` equivale a `<=`
- `min-width` equivale a `>=`

Ao chegar exatamente em `300px`, tanto o menu quanto o botão somem ao mesmo tempo.

Essa é a confusão que aparece ao usar `min-width` e `max-width` apontando para o mesmo valor de breakpoint.

Quando o foco está só no que se está construindo, é fácil deixar esse detalhe passar e acabar 45 minutos debugando...

A frustração é real. Para resolver, é preciso usar dois valores diferentes:

- `max-width: 299px`: significa _menor ou igual a 299px_
- `min-width: 300px`: significa _maior ou igual a 300px_

```css
/* Esconde a navegação em tamanhos pequenos */
.nav {
  @media (max-width: 299px) {
    display: none;
  }
}

/* Esconde o toggle em tamanhos grandes */
.toggle {
  @media (min-width: 300px) {
    display: none;
  }
}
```

Assim, quando a viewport chega em `300px`, a navegação aparece e o toggle some. Sem sobreposição.

Para um caso isolado como esse, a solução funciona. Mas quando o projeto tem vários breakpoints, manter esses ajustes de `1px` começa a ficar trabalhoso.

## Conheça as media queries ranges

As **range media queries** (ou intevalos de media queries) resolvem esse problema sem precisar deslocar breakpoints manualmente.

Basta usar operadores de comparação para escrever a mesma regra de forma mais legível:

```css
/* Menor ou igual a 300px */
.nav {
  @media (width <= 300px) {
    display: none;
  }
}

/* Maior que 300px */
.toggle {
  @media (width > 300px) {
    display: none;
  }
}
```

Isso fica muito mais claro porque é possível ler os operadores e entender a lógica diretamente, sem ter que "decifrar" o que `min-` ou `max-` querem dizer.

Na figura abaixo, as três versões do exemplo viraram uma mesa de fim de curso: o carro marca a largura da viewport, e cada calço cobre o intervalo em que a media query de um elemento vale. Troque a versão e arraste sobre a figura para mudar a viewport. O certo é ter sempre exatamente uma lâmpada acesa, e as duas primeiras versões falham em larguras diferentes.

> **Figura interativa:** uma mesa de fim de curso em que o carro marca a largura da viewport, de 298px a 302px; um calço por media query levanta o rolete do elemento que ela esconde e apaga a lâmpada dele, e cada versão do exemplo deixa as duas lâmpadas apagadas, as duas acesas ou só uma. Disponível na versão HTML desta página.

Essa sintaxe faz parte do módulo <a href="https://www.w3.org/TR/mediaqueries-4/#mq-range-context" target="_blank" rel="noopener noreferrer">Media Queries Level 4</a>.

## Por que usar range media queries?

### Legibilidade

São mais fáceis de ler e entender. Ao bater o olho no CSS, dá para perceber o que a regra significa sem precisar adivinhar. E isso facilita muito a conferência e debug.

### Bem suportadas

<a href="https://webstatus.dev/features/media-query-range-syntax">O suporte dos principais navegadores tem status de Amplamente Disponível</a> desde março de 2023.

### Facilita os intervalos

Quando o objetivo é limitar parte do design entre dois breakpoints, a sintaxe fica bem mais enxuta:

```css
/* Antes */
.section {
  @media (min-width: 300px) and (max-width: 500px) {
    /* estilos para o card */
  }
}

/* Depois */
.section {
  @media (300px <= width <= 500px) {
    /* estilos para o card */
  }
}
```

A leitura segue exatamente o sentido da regra: "largura entre 300px e 500px".

## Não é só para media queries

A sintaxe de intervalos também serve para <a href="https://youtu.be/narcAe-Q7OY">container queries</a>.

Basta trocar `@media` por `@container`:

```css
h1 {
  @container (width >= 300px) {
    color: #fff;
    background-color: var(--brand-1);
  }

  @container (width >= 500px) {
    background-color: hsl(from var(--brand-1) calc(h + 100) s l);
  }
}
```

Veja o resultado:

<video autoplay loop muted playsinline>
  <source src="/images/blog/css-range-syntax-media-queries/page-header.webm" type="video/webm" />
</video>

## Conclusão

As **range media queries** são mais claras, mais fáceis de ler e de debugar e têm suporte sólido entre os principais navegadores.

O suporte é garantido e as vantagens que elas oferecem são muitas. Certamente, vale a pena começar a usá-las a partir do próximo projeto.

## Perguntas frequentes

### Trocar para `max-width: 299px` não resolve de vez o problema do breakpoint?

Quase, mas sobra uma brecha. A largura da viewport nem sempre é um número inteiro de pixels: com zoom ou em telas de alta densidade, ela pode valer algo como `299.5px`. Nesse ponto, nem `max-width: 299px` nem `min-width: 300px` valem, e os dois elementos aparecem. [A própria especificação aponta essa falha](https://www.w3.org/TR/mediaqueries-4/#mq-range-context) dos prefixos `min-` e `max-` e recomenda a range syntax, em que `width <= 300px` e `width > 300px` cobrem todos os valores sem deixar espaço entre eles.

### Posso misturar `<` e `>` num intervalo com dois limites?

Não. No formato com dois limites, [a gramática da especificação](https://www.w3.org/TR/mediaqueries-4/#mq-range-context) só aceita os dois operadores apontando para o mesmo lado: `300px <= width <= 500px` ou `500px >= width >= 300px`. Algo como `300px <= width >= 500px` não casa com a gramática, e uma media query assim é trocada por `not all` na leitura do CSS. Nenhum erro aparece no console: os estilos de dentro simplesmente nunca se aplicam. Outro detalhe da mesma seção é que não pode haver espaço entre `<` e `=`.

### A range syntax funciona com outras características além de `width`?

Funciona com qualquer característica do tipo intervalo, aquela que mede uma quantidade. O [MDN mostra](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media), por exemplo, `(height > 600px)` ao lado de `(400px <= width <= 700px)`. Já as características discretas, que só aceitam um conjunto fixo de valores, [não têm comparação](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Media_queries/Using) e continuam no formato `(característica: valor)`. A mesma regra vale para as [container queries](#não-é-só-para-media-queries).

## Teste seus conhecimentos

**Pergunta 1.** Com a viewport em exatamente `300px`, o que acontece com a navegação e com o toggle?

```css
.nav {
  @media (max-width: 300px) {
    display: none;
  }
}

.toggle {
  @media (min-width: 300px) {
    display: none;
  }
}
```

- Só a navegação some, porque `max-width` vem primeiro
  A ordem não decide nada aqui: cada regra mira um elemento diferente. As duas condições são testadas e as duas são verdadeiras.
- Só o toggle some, porque `300px` já conta como tela grande
  Para `min-width` conta, mas para `max-width` também: `max-width: 300px` inclui os `300px`.
- Os dois somem ao mesmo tempo **(correta)**
  `max-width` equivale a `<=` e `min-width` equivale a `>=`. Em `300px`, as duas condições são verdadeiras.

Os dois somem. `max-width: 300px` significa "menor ou igual a `300px`" e `min-width: 300px` significa "maior ou igual a `300px`", então exatamente em `300px` as duas media queries valem. É o bug que leva muita gente a escrever `max-width: 299px`.

**Pergunta 2.** Qual par de condições esconde exatamente um dos dois elementos em qualquer largura, sem deslocar o breakpoint em `1px`?

- `(width <= 300px)` na navegação e `(width > 300px)` no toggle **(correta)**
  Um operador inclui o `300px` e o outro não. Toda largura cai em exatamente uma das condições.
- `(width < 300px)` na navegação e `(width > 300px)` no toggle
  Em exatamente `300px`, nenhuma das duas condições vale, e os dois elementos aparecem juntos.
- `(width <= 300px)` na navegação e `(width >= 300px)` no toggle
  É o mesmo problema de `max-width` com `min-width`: em `300px`, as duas condições valem e os dois somem.

A resposta é `<=` de um lado e `>` do outro. Com os operadores de comparação, dá para dizer de que lado fica o valor do breakpoint, sem o truque do `299px`.

**Pergunta 3.** Qual range query equivale a `(min-width: 300px) and (max-width: 500px)`?

- `(300px < width < 500px)`
  Com `<`, os próprios `300px` e `500px` ficam de fora. `min-width` e `max-width` incluem os limites.
- `(300px <= width <= 500px)` **(correta)**
  `min-width` vira `>=` e `max-width` vira `<=`. Como os dois limites estão incluídos, os operadores levam o sinal de igual.
- `(width <= 300px) and (width >= 500px)`
  Os operadores estão invertidos. Nenhuma largura é ao mesmo tempo menor que `300px` e maior que `500px`, então a condição nunca vale.

A equivalente é `(300px <= width <= 500px)`. `min-width` significa `>=` e `max-width` significa `<=`, e a range syntax permite escrever o intervalo inteiro numa condição só, lida como "largura entre `300px` e `500px`".

---

Fonte: [dpw - desenvolvimento para web](https://dpw.dev/) (pt-BR).
Guia para agentes: https://dpw.dev/llms.txt
Índice completo: https://dpw.dev/sitemap-index.xml
Feed: https://dpw.dev/rss.xml
