DEV Community

Cover image for Responsividade CSS 101 - Breakpoints
Camilo Micheletto
Camilo Micheletto

Posted on

Responsividade CSS 101 - Breakpoints

Responsividade é a capacidade de um layout se adaptar ou "responder" as mudanças de viewport. Uma das formas mais comuns de se fazer isso era usando @media com o breakpoint mobile mais apropriado da época e construindo à partir dele.

Mas existem outras formas de se usar breakpoints


Breakpoints

Breakpoints são valores de max-width ou min-width que demarcam a mudança de um tipo de layout pra outro. Esses valores geralmente vem de um consenso de época sobre quais são as larguras de dispositivos mais comuns.

A exemplo, a tabela de breakpoints do Bootstrap grid na sua versão 5.

 

👍 Prós

  1. Faz com que os breakpoints façam parte do design system.
  2. Dão mais previsibilidade do aspecto do site em diferentes tamanhos de tela para designers.
  3. Garantem a integridade nos dispositivos mais populares.
  4. Exige menos conhecimento de CSS pra manter.

 

✋ Contras

  1. O problema "tá quebrando no meu dispositivo" acaba sendo solucionado com excessões ou mais um breakpoint.
  2. Limita as capacidades do navegador e dos próprios containers de gerir o layout de forma automática.
  3. Exige CSS extra e as vezes HTML também.

 

Então uso ou não uso breakpoints?


Seja você mesmo seu próprio breakpoint

Não dá pra falar breakpoint sem falar break. Não faz sentido você construir seu site ao redor de pontos de quebra se ele não quebrar. Não faz sentido você ter um breakpoint <=786px se por causa de um sidebar lateral seu site precisa mudar de layout antes disso.

 

👍 Quando usar breakpoints

  • Preciso de uma experiência customizada pra determinado dispositivo.
  • Por um requisito específico de layout, meu site quebra em determinado tamanho de viewport.
  • Pra determinar carregamento de arquivos de CSS pra visualizações específicas.
  • Quando você tá usando um framework CSS que já funciona dentro dessa lógica.

 

✋ Quando não usar breakpoints

  • Porque o xpto usa.
  • Porque só dá pra fazer assim.

Se liga ai que é hora da revisão

Pra entender outras formas de pensar layout que não sejam <div> como colunas e muitos breakpoints, vou usar esse layout que peguei no Pinterest de exemplo.

Layout com 2 linhas e 3 colunas. Na primeira linha um card ocupando duas colunas e um ocupando uma coluna. Abaixo 3 cards ocupando uma coluna cada

 

Como esse layout não vinha com protótipo, fiz um protótipo demonstrando como ele ficaria no viewport de tablet e web em tela cheia.

Protótipo demonstrando os layouts em outros viewports

 

Antes de simplesmente pegar 3 breakpoints na internet e criá-los, vamos analisar o layout:

  • O card principal ocupa duas colunas nos layouts wide e tablet, no mobile ocupa uma coluna só, mas um espaço vertical maior.
  • Não há mudança substancial nos cards que ocupam uma coluna só, eles se mantém o mesmo de acordo com o grid.
  • Como os elementos da segunda linha precisam sempre estar alinhados com o da primeira, é interessante usar grid. Com o flexbox precisaríamos ou definir larguras fixas pra cada flex-item, usar % no flex-basis ou criar <div> no HTML pra serem as "colunas", influenciando negativamente a ordenação natural dos itens no HTML.

 

Marcação

A marcação inicial vai ser simples, uma lista não ordenada de cards:

<ul class="layout">
  <li class="card">1</li>
  <li class="card">2</li>
  <li class="card">3</li>
  <li class="card">4</li>
  <li class="card">5</li>
</ul>
Enter fullscreen mode Exit fullscreen mode

 

CSS inicial

* { padding: 0; margin: 0; }

body {
  min-block-size: 100vh;
  background-color: #ccc;
  padding: 2ch;
}

.layout {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(320px, 1fr)
  );
  gap: 2ch;
  height: 100vh; width: 100%;
  list-style-type: none;
}

.card:nth-child(1) { background-color: #BFDAF1; }
.card:nth-child(2) { background-color: #C1EACF; }
.card:nth-child(3) { background-color: #EFD1D0; }
.card:nth-child(4) { background-color: #F2E2C7; }
.card:nth-child(5) { background-color: #CDCCE9; }

Enter fullscreen mode Exit fullscreen mode

 

  • min-block-size: 100vh; no body diz que o tamanho mínimo do eixo-y (block) é de 100vh (viewport height). Isso diz explícitamente que o body tem que ser pelo menos da altura da tela toda, o que permite ele crescer pra além disso, se necessário.

  • Em .layout, a função repeat() vai usar o algoritmo de auto-fit como primeiro parâmetro. Isso sinaliza o repeat que ao invés de repetir uma quantidade x de vezes, ele crie quantas colunas couberem no espaço disponível dele.

  • O minmax(320px, 1fr) vai fazer com que cada coluna seja no mínimo de 320px de largura, mas fiquem maiores caso haja mais espaço disponível.

🧐 Se ficou dúvidas, falo mais sobre esse algoritmo de layout no meu artigo sobre CSS Grid (link abaixo).

 

O resultado do layout:

Layout se adaptando quebrando cada caixa de coluna

 

Funciona! Mas temos alguns problemas.

  • O primeiro card tem que ocupar 2 colunas.
  • O layout não pode conter mais que 3 colunas.
  • O primeiro card precisa ser maior no mobile

 

O primeiro card tem que ocupar 2 colunas

Como estamos usando grid, basta usar grid-column no card pra dizer a ele quantas colunas ele ocupa.

.card:nth-child(1) {
  grid-column:  span 2;
}
Enter fullscreen mode Exit fullscreen mode

Resultado:

Layout responsivo com o primeiro card ocupando duas colunas

 

O layout não pode conter mais que 3 colunas

Acima de 1320px o layout passa a ter 4 colunas. Isso se deve pois em 1320px cabem 3 cards de 430px (1290px) + o gap (2 * 16px), mas acima desse valor passam a caber 4 cards de 320px, logo o layout se reajusta.

Pra alterar como o layout se comporta depois dessa largura, criamos um breakpoint:

@media (min-width: 1320px) {
   .layout {
     grid-template-columns: repeat(3, minmax(320px, 1fr));
   }
}
Enter fullscreen mode Exit fullscreen mode

 

Alternativamente, podemos usar variáveis CSS pra não precisar reescrever todo valor da propriedade:

.layout {
  /* código omitido */
  grid-template-columns: repeat(
    var(--index, auto-fit),
    minmax(320px, 1fr)
  );
  /* código omitido */
}

/* Breakpoint injetando o --index no .layout */
@media (min-width: 1320px) {
  .layout { --index: 3; }
}

Enter fullscreen mode Exit fullscreen mode

 

O primeiro card precisa ser maior no mobile

Precisamos que quando couber apenas uma coluna, que o primeiro card tenha a altura maior, cobrindo 100vh da tela.

Pensando no exemplo anterior, podemos criar uma variável --column pro grid-column do primeiro card, que será span 2 quando em um viewport maior, mas 1 / -1 quando em apenas uma coluna.

 

📝1 / -1 é utilizado no grid-column, significando que você quer que a coluna comece da primeira e vá até a última, independente de quantas colunas tenham.

 

/* Alteramos o valor de grid-column do card pra uma  variável com valor default de `span 2` */
.card:nth-child(1) {
  grid-column:  var(--column, span 2);
}

/* Redesignamos o valor dela dentro da media query */

@media (max-width: 720px) {
  .card { --column: 1 / -1; }
  .card:first-child { height: 100vh; }
}

Enter fullscreen mode Exit fullscreen mode

 

📝 o bacana de usar variáveis CSS pra propriedades que você precisa reescrever é que você corre menos risco de a media query ter menos especificidade que o próprio seletor e não funcionar corretamente.

 

Você pode brincar aqui com o resultado final:


Finalmente

Pensei seriamente em fazer um artigo voltado pro público iniciante, porém responsividade não é um tema fácil. Pessoas iniciantes vão usar mais media queries, vão fazer hacks de CSS ou usar frameworks, e não tem nada de errado nisso.

Algoritmos de layout mais complexos são adquiridos com prática, tempo e muita leitura. Se você sentiu dificuldade ao entender esse artigo com um ano ou menos de estudo, saiba que eu levei um pouco mais de 4 anos pra ser capaz de escrevê-lo.

Tá tudo bem com suas media queries e gambiarras. O ponto do post é que você não precisa ser só bom em gambiarra, se você quiser. O CSS tem muito a oferecer se você tiver um pouco mais de persistência.

Top comments (15)

Collapse
 
mouro profile image
Rodrigo Luiz

Boa tarde, Camilo, pode explicar porque usas a unidade de medida ch?
Por exemplo, padding: 2ch, tenho usado px, rem, em, porem nao sei qual seria a melhor prática, um padrão para qualquer tipo de layout e parabéns por mais conteúdo maravilhoso.

Collapse
 
lixeletto profile image
Camilo Micheletto

A melhor prática é você usar sabendo por que usou, entende?

Eu gosto de usar ch no padding e na margem pois como ele representa a largura do caractere 0, eu sei de cabeça + ou - como vai ficar, é previsível pra mim.

Eu não usaria em produção pra esse caso, até porque provavelmente a empresa tem seu próprio design system com espaçamentos já definidos;

Associar unidades CSS diretamente à elementos ou propriedades é um erro. Aprender pra o que elas servem e defender seus casos de uso é a forma mais produtiva de abordar.

Collapse
 
matheusfilg profile image
Matheus Filgueiras

Artigo insano e complexo, mudou minha forma de ver responsividade como algo simples devido a frameworks e hacks, tem muito o que explorar e aprender em como atender as necessidades de determinados layouts

Parabéns 💜

Collapse
 
lixeletto profile image
Camilo Micheletto

Graças a muitas perguntas que rolaram no twitter (e eu vou respondendo por aqui com o tempo). É um mundo a parte, mas vale a pena se debruçar

Collapse
 
raulferreirasilva profile image
Raul Ferreira

Não me canso e ler seus posts, se tá doido, ansioso pra por em pratica tudo que estou aprendendo e ter duvidas para trazer aqui KKKKK, muito obrigado por compartilhar seu conhecimento de uma forma tão clara e bem escrita 🦤.

Collapse
 
lixeletto profile image
Camilo Micheletto

Quando por em prática, se for sua vibe, escreva sobre! Ficarei feliz ajudar e compartilhar

Collapse
 
gustavohqo profile image
Gustavo

Cara, ce tá de parabéns! o artigo ficou muito bom! Me deu muitas ideias, você merece um abraço!

Muito obrigado!

Collapse
 
lixeletto profile image
Camilo Micheletto

Opaaa, que honra mano!

Collapse
 
jessilyneh profile image
Jessilyneh

Salvando pra ler mais tarde e tenho certeza que ficou muito foda

Collapse
 
lixeletto profile image
Camilo Micheletto

Obrigado queridíssima!

Collapse
 
gabrielgomeso profile image
Gabriel Gomes de Oliveira

Quando você usa

grid-template-columns: repeat(
    var(--index, auto-fit),
    minmax(320px, 1fr)
  );
Enter fullscreen mode Exit fullscreen mode

E o --index só é definido no breakpoint de min-width: 1320px, significa que o var() vai ver se tem valor pra index, se não vai jogar pra auto-fit?

Collapse
 
lixeletto profile image
Camilo Micheletto

Exatamente!
Se você é familiarizado com Javascript, é quase como:

const = gridTemplateColumns(repeat(index || 'auto-fit'), minmax())
Enter fullscreen mode Exit fullscreen mode
Collapse
 
gabrielgomeso profile image
Gabriel Gomes de Oliveira

Muito bom! Ótimo artigo, deu pra entender bem!! Não tinha noção que o var() fazia isso tbm, irado

Thread Thread
 
lixeletto profile image
Camilo Micheletto

Ele é poderosíssimo! Quero muito escrever um artigo só sobre ele

Collapse
 
eriveltondasilva profile image
Erivelton da Silva

Tbm mudou a minha forma de pensar responsividade, parabéns pelo trabalho, meu irmão 👏🏻👏🏻🙏🏻