Valores absolutos e relativos em CSS: quando usar px, % e rem
Tags: valor, absoluto, relativo, css
Published: 2022-07-12 18:27:57

## Entenda as melhores situações no CSS para usar valores absolutos, como pixel, e valores relativos, como percentual ou rem.
 
O que é melhor: definir valores absolutos ou relativos em CSS?
 
É claro que depende.
 
Por exemplo, se John pesa 90kg, não é preciso nenhuma informação a mais para saber seu peso. Pois kg é um valor absoluto.
 
Agora imagine que Doe pese 85%. Arrisco dizer que a primeira coisa que você pensou foi:
 
- *85% de quê? Quantos kg Doe pesa?*
 
Não é possível responder, já que percentual é um valor relativo. E nesse caso você precisa de uma **referência**.
 
Se a **referência** para o peso de Doe for John, posso afirmar que Doe pesa 76,5kg (90 x 0,85 = 76,5).
 
Agora, se a **referência** para o peso de Doe for o peso do próprio Doe há 1 ano, o seu peso pode não ser o mesmo.
 
![Um ovo branco grande ao lado de um ovo marrom pequeno, mostrando que tamanho é algo relativo por comparação](https://www.datocms-assets.com/64896/1653005226-daniele-levis-pelusi-4mpsem3egak-unsplash.jpg)
 
**De forma teórica, absoluto é aquilo que existe por si só, já o relativo precisa de uma referência para existir.**
 
Mas voltando a falar de CSS... eu sempre utilizo:
 
- **Valores relativos** para propriedades CSS que **variam** de acordo com alguma variável (como por exemplo o tamanho da janela, o elemento pai ou elemento root)
- **Valores absolutos** para propriedades CSS que **não variam**
 
Conforme a [W3Schools, existem diversos tipos de medidas absolutas e relativas](https://www.w3schools.com/cssref/css_units.asp). Veja agora as mais usadas:
 
## Valores absolutos em CSS
 
Apesar de você poder usar [centímetros](https://www.w3schools.com/cssref/tryit.asp?filename=trycss_unit_cm) e [polegadas](https://www.w3schools.com/cssref/tryit.asp?filename=trycss_unit_in) em propriedades CSS, o mais recomendado (e usado) é pixels mesmo.
 
Quando um elemento possui `width: 800px`, a sua largura nunca será diferente disso. Mesmo que a janela tenha menos do que 800px e crie aquela barra de rolagem lateral que todo front-end ama odiar.
 
![Blocos de cores vermelho, verde e azul representando os pixels na tela](https://www.datocms-assets.com/64896/1653005462-michael-maasen-akygy_ymfqo-unsplash.jpg)
 
As duas principais vantagens dos valores absolutos em CSS são:
 
- Maior **previsibilidade**, pois não haverá surpresas em como seu elemento irá renderizar. É aquela medida e pronto
- Melhor **desempenho**, já que o navegador não precisará calcular nada, a medida em pixels já está bem explícita
 
Mas não pense em trocar os valores relativos do CSS por valores absolutos, para melhorar o desempenho. Caso contrário, cenas como essa seriam comuns:
 
```css
@media screen and (min-width: 320px) {
  .container {
    width: 320px;
  }
}

@media screen and (min-width: 321px) {
  .container {
    width: 321px;
  }
}

@media screen and (min-width: 322px) {
  .container {
    width: 322px;
  }
}

/* ... */

@media screen and (min-width: 1600px) {
  .container {
    width: 1600px;
  }
}

/* E contando... */
```
 
Isso causaria o efeito contrário, tornando o seu código gigante e ineficiente.
 
Você deve ter percebido que a primeira grande desvantagem de usar valores absolutos é que eles não se adaptam a diferentes cenários. Logo, uma seção com 400px de largura terá essa medida em um iPhone, tablet, notebook e tela ultrawide.
 
Para evitar isso, você pode usar os valores relativos:
 
## Valores relativos em CSS
 
**Diferente dos valores absolutos, os valores relativos precisam de uma referência para existir.**
 
Exemplo:
 
```html
<div class="container">
  <div class="item">Item 1</div>
  <div class="item">Item 2</div>
  <div class="item">Item 3</div>
</div>
```
 
```css
.container {
  width: 800px;
}

.item {
  width: 50%;
}
```
 
Em CSS, valores percentuais usam como referência o elemento pai. Então, a referência para a largura do `.item` é `.container`.
 
Nesse caso, o navegador realiza um cálculo para descobrir que a largura de `.item` deve ser 400px:
 
50% de 800px = **400px**
 
É por isso que todo front-end bate cabeça (eu ainda bato) para fazer funcionar o bendito `height: 100%` (e às vezes não funciona). Porque o elemento já possui altura de 100% em relação ao seu elemento pai.
 
Vou fugir um pouco do assunto, mas valores em percentual (%) não são relativos ao tamanho da janela.
 
- Se você quiser que algo fique da altura da janela, use `height: 100vh` (vh = viewport height)
- Se você quiser que algo fique da largura da janela, use `width: 100vw` (vw = viewport width)
 
"*Então quer dizer que, quando eu uso um valor relativo, é assim que o navegador carrega aquele elemento?*"
 
É, não é bem assim.
 
## Todo elemento possui um valor absoluto
 
Como você leu no começo do artigo, valores relativos precisam de uma referência para serem definidos.
 
Vou continuar no exemplo anterior, digamos que você mude a largura do `.container` para 700px:
 
```css
.container {
  width: 700px;
}

.item {
  width: 50%;
}
```
 
O cálculo é refeito, para descobrir a nova largura de 350px:
 
50% de 700px = **350px**
 
Mas por que o navegador faz esses cálculos? Essa foi a dúvida que me fez querer escrever esse post. E a resposta encontrei nesse [artigo do Google sobre layout](https://web.dev/critical-rendering-path-render-tree-construction/).
 
**Basicamente, todas as medidas relativas são convertidas em pixels absolutos na tela.**
 
Isso quer dizer que, mesmo que seu elemento possua um `width: 50vw`, ele terá um valor absoluto atrelado a ele. Se sua janela tiver 700px de largura, então o valor absoluto será `width: 350px`.
 
"*Mas e se eu redimensionar minha janela para 600px de largura?*"
 
Então seu elemento passará a ter `width: 300px`.
 
Veja a magia acontecendo você mesmo:
 
![O navegador recalculando a largura de uma div em pixel, conforme muda o tamanho da janela, mesmo que o width tenha sido definido em vw](https://www.datocms-assets.com/64896/1653005822-width.gif)
 
## O que é melhor: valores absolutos ou relativos?
 
A resposta simples e direta é: qualquer um, desde que o outro não seja melhor (risos).
 
![Escrita "laugh" em letra neon (risada em inglês)](https://www.datocms-assets.com/64896/1653006346-tim-mossholder-imld5dbclm4-unsplash-1.jpg)
 
Agora sério, é claro que depende.
 
Ao longo desse texto eu expliquei algumas características tanto de valores absolutos, quanto de relativos.
 
Basta você adaptar a sua situação a essas características, e a resposta talvez não pareça tão distante.
 
Vou deixar aqui algumas preferências pessoais (NÃO É REGRA!).
 
### Valores para font-size em CSS
 
Nessa propriedade, gosto de usar valores em `rem`:
 
```css
html {
  font-size: 16px;
}

h1 {
  font-size: 3rem; /* 48px */
}

p {
  font-size: 1rem; /* 16px */
}

.small {
  font-size: 0.8rem; /* 12,8px */
}
```
 
`1rem` é igual ao `font-size` do elemento root (na web, também chamado de tag `<html>`). Então para descobrir o valor em pixels, basta multiplicar o valor em `rem` pelo `font-size` do root.
 
Deixei comentado no código acima o valor em pixels calculado.
 
A grande vantagem dessa propriedade é facilitar a responsividade do site. Basta que você altere o tamanho da fonte do elemento root.
 
### Valores para width, height e propriedades de layouts em CSS
 
Nessas propriedades, sempre dou preferência para usar valores percentuais. Isso porque na maioria dos casos, seu tamanho depende do elemento pai.
 
Para fazer um modal, overlay e outros elementos posicionados, uso `vw` para definir `width` e `vh` para `height`. Isso serve apenas para garantir que o elemento use a totalidade da janela como referência. Mesmo assim, valores percentuais também funcionam.
 
Em algumas situações, usar a propriedade `max-width` e/ou `max-height` torna seu código mais dinâmico ainda. Veja um exemplo:
 
```css
.container {
  width: 100%;
  max-width: 992px;
}
```
 
Isso fará com que o elemento ocupe toda a largura do elemento pai (`width: 100%`). Porém quando esse elemento pai for maior do que 992px, ele ficará limitado a esse tamanho (`max-width: 992px`).
 
Isso não torna o elemento necessariamente responsivo, mas às vezes evita o uso Media Queries.
 
Sem a propriedade `max-width`, o elemento ficaria um "chiclete" (esticaria infinitamente junto com o elemento pai).
 
### Valores para margin e padding em CSS
 
Esse é outro caso onde o uso da medida em `rem` é muito bem vindo.
 
Isso porque os espaçamentos devem se adequar a diferentes tamanhos de telas. E quando o `font-size` do elemento root é atualizado pelas Media Queries, todo o resto se adapta junto.
 
Outra alternativa ao `rem` é definir variáveis do CSS:
 
```css
:root {
  --spacing-small: 5px;
  --spacing-medium: 10px;
  --spacing-large: 15px;
}

@media screen and (min-width: 768px) {
  :root {
    --spacing-small: 20px;
    --spacing-medium: 25px;
    --spacing-large: 35px;
  }
}

.container {
  padding: var(--spacing-large);
}

.card {
  padding: var(--spacing-small);
}
```
 
Assim, apesar de usar pixels que são valores fixos, a responsividade não fica tão complicada.
 
## Callback
 
Acho que fica legal explicar as principais diferenças em uma tabela:

| Medidas absolutas (px)       | Medidas relativas (%, rem, vw, vh)    |
|------------------------------|---------------------------------------|
| Os valores existem por si só | Os valores precisam de uma referência |
| Exige menos do navegador (melhor performance)	| Exige que o navegador calcule o valor em pixels |
| Os valores são mais previsíveis	| Os valores gerados no navegador podem gerar algumas surpresas |
 
Acabei de ler esse [artigo que fala sobre acessibilidade em pixel, em e rem](https://www.joshwcomeau.com/css/surprising-truth-about-pixels-and-accessibility/) e dá dicas de como decidir qual medida usar. A frase chave desse artigo para mim foi:
 
> *Esse valor deve aumentar à medida que o usuário aumenta o tamanho da fonte padrão do navegador? Esta questão é a raiz do modelo mental que utilizo. Se o valor aumentar com o tamanho da fonte padrão, eu uso `rem`. Caso contrário, eu uso `px`.*
>> *Josh W Comeau*
 
Se tiver dúvidas, sugestões ou leu algo que *não é bem assim* como eu escrevi, pode colocar nos comentários ;)
 
Obrigado!