Responsividade CSS 101 - Breakpoints

lixeletto

Camilo Micheletto

Posted on October 3, 2023

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.

💖 💪 🙅 🚩
lixeletto
Camilo Micheletto

Posted on October 3, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related