A anatomia das Media Queries
Tags: beginners, css
Published: 2021-03-04 23:56:51

_Geralmente a frase "pô usa media queries" vem como resposta pra pergunta "como posso fazer para deixar meu site mais resposivo?". Mas além de não ser a única **at-rule** (traduzindo literalmente, regra @), a @media tem muitas outras capacidades além de auxiliar na responsividade._

Nesse post iremos conhecer mais sobre a declaração `@media` e ver um panorama geral sobre suas capacidades.

&nbsp;

## O que são at-rules?
São basicamente declarações que dizem como o seu CSS deve se comportar, elas contém sempre um identificador (Ex: media, keyframes, supports) e podem ou não conter parâmetros e blocos. Elas são divididas em duas categorias, as **normais** e as **aninhadas**.
&nbsp;

### At-rules normais
São declarações que podem receber parâmetros mas não recebem blocos de código, servem pra configuração ou importação de documentos externos:

- `@charset`
Declaração utilizada para definir a faixa de caracteres Unicode que seu documento CSS vai utilizar (ex: UTF-8). O browser faz boa parte do trabalho, logo a sua declaração não é obrigatória, mas é interessante utilizá-la caso vá usar um grupo de caracteres diferenciado.

- `@import`
Essa declaração importa arquivos de uma URL para serem carregados juntamente com o seu CSS. Ela é composta basicamente da declaração `@import` seguida de um link, mas pode uma lista de media-queries como condições de carregamento:

```css
/* Declaração básica, pode receber desde URL externas
até caminhos relativos */
@import "./main.css";

/* Carregando um arquivo de CSS apenas para dispositivos de mão
 com no máximo 400px de largura e que suportam display: flex */
@import url("mobile.css") supports(display: flex) handheld and (max-width: 400px);

/* Carregando CSS especificamente para o formato 
de paisagem
@import url('landscape.css') screen and (orientation:landscape);
```
&nbsp;
> 💡 !importante
O `@import` funciona de maneiras diferentes no CSS e no Sass/SCSS. Enquanto no CSS a importação carrega os documentos junto com o seu, no Sass o compilador coloca os arquivos importados dentro do mesmo documento. Atualmente o `@import` do Sass está sendo deixado de lado no lugar de `@use` e `@forward` que possuem maior controle de namespacing, permitem personalizar o carregamento das folhas de estilo usando a função `with()`

- `@namespace`
Declarando um namespace você consegue especificar dentro de qual contexto as suas declarações estão, seja HTML, SVG, XHTML ou XML por exemplo:

```css
/* declaração <prefixo> url | string*/
@namespace svg "http://www.w3.org/2000/svg";

/* Utilizamos da seguinte forma: */

svg|a {
    /* um <a> dentro de um contexto SVG */
}   
```
&nbsp;

### At-rules de grupos aninhados
São declarações que podem recebe trechos de código dentro delas que vão ser executados caso as condições se apliquem, as 3 mais comuns são `@media`, `@keyframes` e `@supports`.

&nbsp;
## @media
Primeira coisa sobre o `@media` é que a expressão *media queries* se refere às condições que passamos pra essa declaração, não a declaração em si. A parte da *query* é a expressão que vem depois de `@media` que vai sempre retornar `true` ou `false`. Quando a *media query* for verdadeira, as regras que estão dentro dela serão utilizadas no lugar das que já estão declaradas na raiz do documento.
![Uma vez que um bloco de uma at-rule retorna verdadeiro, se ela tem um bloco de código se referenciando a um seletor específico, o seletor ja existente é substituído pelo de dentro do bloco](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/apwcgvt2b1tkdixxeh7v.png)

```css
/* Exemplo retirado do MDN */

/* Na raiz do código */
article {
  padding: 0;
}

/* Se o documento tiver a largura de até 900px,
o seletor <article> vai receber o código da @media
abaixo, padding que já havia sido declarado será
sobreposto e a propriedade margin será acrescentada */
@media screen and (max-width: 900px) {
  article {
    padding: 1rem 3rem;
    margin-top: 5px;
  }
}

/* Aninhado com outra at-rule, o bloco dentro do
@media só será executado se a largura do documento
for de até 900px e se o navegador possuir suporte
para flexbox*/
@supports (display: flex) {
  @media screen and (max-width: 900px) {
    article {
      display: flex;
    }
  }
}

```
Na declaração acima, a *media query*, ou seja, às condições para que o bloco de código `.article` seja executado são de que o tipo de mídia seja uma tela e que sua largura máxima seja de 900px. Se as condições forem verdadeiras, o elemento `.article` vai receber a propriedade `padding: 1rem 3rem;` que ira ser acrescentada a classe original ou substituirá caso essa classe já tenha um `padding` declarado.

Uma declaração @media pode ser formada por *media types* e *media conditions*, que juntos formam uma *media query* ou *media condition*:

![Anatomia de um @media - Referência retirada da especificação oficial W3 (https://www.w3.org/TR/mediaqueries-4/#media), 24-02-2021](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yoci8nerbc28a92m1zcw.png)

&nbsp;

### Media types
*Media types* se refere a que tipo de mídia o código se aplica, não especificamente dispositivos como celulares e TV, mas também mídia impressa e sintetizadores de voz, as *media types* são: 

- `all`
O código é aplicável para todos as saídas de mídia, é o valor padrão.

- `screen`
O bloco de código é aplicável para telas.

- `print`
Código específico para impressão, muito útil para remover links, navegações e interações que não serão visíveis no documento impresso.

- `speech`
Configuração específica para sintetizadores de voz.

Usamos os media types da seguinte forma: 

```css
/* O media type 'all' é implícito se nenhum 
outro é declarado */

@media screen { /* ... */}
@media print{ /* ... */}
@media speech{ /* ... */}


/* Podemos utilizar a mesma regra para diferentes mídias
separando-os por vírgula */

@media screen, print { /* ... */ }


/* Podemos declarar no contexto de importação */

@import url(example.css) screen and (color), print and (color);

```

Também podemos declará-las no elemento `<link>` ao carregar seu CSS no HTML:

```css
<link 
  media="screen and (color),print and (color)"
  rel="stylesheet"
  href="example.css"
/>
```
&nbsp;
> 💡 !importante
É possível usar os operadores lógicos `not | or | and` para criar condicionais mais complexas para as suas declarações, eles funcionam tanto para os *media types* quanto pros *media features*:
```css
/* Mídias de tela com largura máxima de 400px */
@media screen and (max-width: 400px) {
  /* ... */
}

/* Condição aplicada em dispositivos com tela que sejam
monocromáticos e possuam suporte para hover (um kindle talvez?)*/
@media screen and not ((color) or (hover)) {
  /* ... */
}
```
&nbsp;
### Media features
Media features são características do user-agent (configurações padrão do navegador), ambiente e dispositivo. Todas essas características podem ser usadas como condições para definir a aplicabilidade do código.

```css
/* Telas que tem no máximo 600px de largura e no mínimo
120ch de altura */
@media screen and (max-width: 600px) and (min-height: 120ch) {
  /* ... */
}

/* Telas cujo a largura é maior ou igual a 800px.
Declarações como width e height são computadas como valores
numéricos até que você declare uma unidade, suportando
assim os operadores lógicos =, >, <, >= e <= */
@media (width >= 600) {
  /* ... */
}
```

Você pode acessar a [lista gigante de *media features* que tem no MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/@media#media_features), mas vou elencar algumas bacanas, inclusive que saíram na especificação de nível 4 e 5 do CSS e que você pode conferir na íntegra no [site da W3](https://drafts.csswg.org/mediaqueries-5/#media-descriptor-table).

- `orientation`
Define regras para dispositivos em retrato (portrait) ou paisagem (landscape).

- `prefers-color-scheme`
Define regras de acordo com o tema configurado no navegador, aceita os valores `light` e `dark`, muito bom para definir o tema escuro do seu site. Ex:
```css
:root {
  --background: #fff;
  --color: #1a1a1a;
}

@media (prefers-color-scheme: dark) {
/* Troca as cores das variáveis quando o tema for escuro */
  :root {
    --background: #1f212b;
    --color: #fff;
  }
}
```
Para saber mais como utilizar essa feature query para fazer temas, leia [esse post](https://css-tricks.com/a-dry-approach-to-color-themes-in-css/) do Christopher Kirk-Nielsen.

- `prefers-reduced-motion`
Define configurações para usuários que tem problemas de leitura ou atenção com páginas muito animadas, [esse post do WebDev](https://web.dev/prefers-reduced-motion/) explica muito bem o contexto dessa feature.
```css
@media (prefers-reduced-motion) {
  .animation {
    /* Aqui você pode deixar a animação mais devagar ou
    completamente estática */
  }
}
```

- `resolution`
Define a configuração de diferentes resoluções de tela, que podem afetar a visualização de fontes e imagens, aceita valores _dpi_(pontos por polegada) ou _dpcm_ (pontos por centímetro):
```css
@media (max-resolution: 300dpi) {
  p {
    background: yellow;
  }
}
```
&nbsp;

## Quero saber mais

Para uma leitura ainda mais aprofundada a respeito do @media recomendo ir direto na [especificação da W3](https://www.w3.org/TR/mediaqueries-4/#media) que apesar de densa tem detalhes **muito** legais que você não encontra em qualquer lugar. Recomendo também esse post [da CSS Tricks](https://css-tricks.com/a-complete-guide-to-css-media-queries/) que fala também sobre como acessar as @media via javascript (sim, é possível) e fala mais sobre _nesting_.

--------

Muito obrigado por chegar até aqui! Tem uma dúvida ou mágoa? Faltou algo? Achou algo de errado? Comenta ai!