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.
👍 Prós
- Faz com que os breakpoints façam parte do design system.
- Dão mais previsibilidade do aspecto do site em diferentes tamanhos de tela para designers.
- Garantem a integridade nos dispositivos mais populares.
- Exige menos conhecimento de CSS pra manter.
✋ Contras
- O problema "tá quebrando no meu dispositivo" acaba sendo solucionado com excessões ou mais um breakpoint.
- Limita as capacidades do navegador e dos próprios containers de gerir o layout de forma automática.
- 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.
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.
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>
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; }
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çãorepeat()
vai usar o algoritmo deauto-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:
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;
}
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));
}
}
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; }
}
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 nogrid-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; }
}
📝 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)
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 💜
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
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.
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.
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 🦤.
Quando por em prática, se for sua vibe, escreva sobre! Ficarei feliz ajudar e compartilhar
Salvando pra ler mais tarde e tenho certeza que ficou muito foda
Obrigado queridíssima!
Cara, ce tá de parabéns! o artigo ficou muito bom! Me deu muitas ideias, você merece um abraço!
Muito obrigado!
Opaaa, que honra mano!
Quando você usa
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?
Exatamente!
Se você é familiarizado com Javascript, é quase como:
Muito bom! Ótimo artigo, deu pra entender bem!! Não tinha noção que o var() fazia isso tbm, irado
Ele é poderosíssimo! Quero muito escrever um artigo só sobre ele
Tbm mudou a minha forma de pensar responsividade, parabéns pelo trabalho, meu irmão 👏🏻👏🏻🙏🏻