Trechos do capítulo "Layout no celular: a tela pequena manda" Curso Frontends com Vibecoding alexandrecaramaschi.com/educacao/frontends-com-vibecoding#layout-mobile Nove trechos. A explicação de cada técnica está no capítulo, em português. Este arquivo guarda só o texto que você cola no projeto. Leia antes o LEIA-ME.txt desta pasta. ================================================================================ ### O que faz: altura de tela cheia que não estoura quando a barra do navegador aparece ### Onde entra: folha de estilo do bloco de destaque e da tela de ação única ### Cuidado: 100vh mede a tela com a barra escondida, e é por isso que o botão cai fora /* Errado: mede a tela com a barra do navegador escondida. No celular o bloco nasce alto demais e o botão cai fora. */ .hero { height: 100vh; } /* Certo: acompanha a barra que aparece e some. */ .hero { min-height: 100dvh; /* dinâmica: segue o movimento */ } /* Para o que PRECISA estar visível na abertura, use o pior caso. */ .checkout-acao { min-height: 100svh; /* pequena: conta com a barra visível */ } ================================================================================ ### O que faz: devolve o espaço do recorte da câmera e da barra de gestos ### Onde entra: a meta de viewport no e o espaçamento de todo elemento fixo nas bordas ### Cuidado: sem viewport-fit=cover no passo 1, os env() do passo 2 voltam zero ================================================================================ ### O que faz: grade que conta as próprias colunas, título fluido e componente que decide pelo espaço recebido ### Onde entra: folha de estilo da vitrine, dos títulos e do cartão reaproveitado em vários lugares ### Cuidado: a consulta de contêiner só funciona se o elemento pai declarar container-type /* 1. A grade conta as colunas. Nenhuma media query envolvida. */ .vitrine { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); } /* 2. Título fluido entre um piso e um teto. */ .titulo { font-size: clamp(1.5rem, 4vw, 3rem); line-height: 1.15; } /* 3. O componente decide pelo espaço que recebeu, não pela janela. */ .slot-do-cartao { container-type: inline-size; } .cartao { display: grid; gap: 8px; } @container (min-width: 400px) { .cartao { grid-template-columns: 120px 1fr; /* foto ao lado do texto */ align-items: center; } } ================================================================================ ### O que faz: alvo de toque confortável, espaço entre alvos vizinhos e gestos que não brigam com a rolagem ### Onde entra: botões de ícone, barras de ação, carrossel e listas dentro de gaveta ### Cuidado: aumentar a área clicável não é aumentar o desenho do ícone /* Alvo confortável mesmo com ícone pequeno. */ .botao-icone { min-inline-size: 44px; min-block-size: 44px; display: grid; place-items: center; /* o ícone de 20px fica centrado no alvo de 44 */ } /* Ícone que não pode crescer: aumente só a área clicável. */ .link-compacto { position: relative; } .link-compacto::after { content: ""; position: absolute; inset: -12px; /* 12px para cada lado viram alvo */ } /* Espaço entre alvos vizinhos: o tamanho sozinho não basta. */ .barra-de-acoes { display: flex; gap: 8px; } /* Carrossel: arrasto lateral sem brigar com a rolagem da página. */ .carrossel { touch-action: pan-y; overflow-x: auto; scroll-snap-type: x mandatory; } /* Lista dentro de gaveta: a rolagem para no fim, sem vazar. */ .gaveta-conteudo { overflow-y: auto; overscroll-behavior: contain; } ================================================================================ ### O que faz: a gaveta fecha no botão voltar do aparelho, em vez de a pessoa sair do site ### Onde entra: componente de cliente em React, chamado pelo painel de filtros ou pelo menu lateral ### Cuidado: sem a limpeza do passo 3, fechar pelo X deixa um voltar morto no histórico "use client"; import { useEffect } from "react"; export function useFecharNoVoltar(aberta: boolean, fechar: () => void) { useEffect(() => { if (!aberta) return; // 1. Ao abrir, empilha uma entrada no histórico. window.history.pushState({ gaveta: true }, ""); // 2. O botão voltar do aparelho dispara popstate: aqui só fechamos. const aoVoltar = () => fechar(); window.addEventListener("popstate", aoVoltar); return () => { window.removeEventListener("popstate", aoVoltar); // 3. Se a gaveta fechou pelo X ou pelo Esc, desempilha a entrada // para não deixar um voltar "morto" no histórico. if (window.history.state?.gaveta) window.history.back(); }; }, [aberta, fechar]); } ================================================================================ ### O que faz: os dois caminhos honestos da tabela na tela estreita, rolar ou virar cartão ### Onde entra: extrato, relatório e qualquer tabela que hoje estoura a largura do celular ### Cuidado: a caixa que rola precisa de tabindex, role e rótulo, ou ela existe só para o mouse
...
================================================================================ ### O que faz: campos que sobem o teclado certo e aceitam o preenchimento automático do aparelho ### Onde entra: formulário de cadastro, checkout e confirmação por código ### Cuidado: o trecho de script rola o campo em foco para o centro; teste com o teclado aberto em aparelho real ================================================================================ ### O que faz: o celular baixa a versão pequena da foto, e o espaço fica reservado antes de ela chegar ### Onde entra: toda imagem servida direto por , e o atributo sizes também no next/image ### Cuidado: sem o sizes, o navegador supõe a largura inteira da janela e baixa mais do que precisa Tênis de corrida azul, vista lateral ================================================================================ ### O que faz: pede ao agente a passada de celular inteira, com critérios que você confere na tela ### Onde entra: a caixa de conversa do agente, com o arquivo da tela aberto ### Cuidado: troque o trecho entre colchetes pela descrição da sua tela antes de enviar Revise esta tela para celular. Ela é um [descreva: checkout / listagem de produtos / formulário de cadastro] em Next.js com Tailwind, e o público chega majoritariamente por celular Android em rede móvel. Aplique, mostrando o diff de cada arquivo: 1. Troque toda altura em vh pelas unidades certas: 100dvh nos blocos de tela cheia e 100svh no que precisa estar visível na abertura. 2. Garanta viewport-fit=cover na meta de viewport e envolva em max() todo espaçamento de elemento fixo nas bordas, com env(safe-area-inset-*). 3. Substitua listas de pontos de quebra por grade com auto-fit e minmax onde o arranjo for de cartões de mesmo tipo. 4. Leve todo alvo de toque para no mínimo 44 por 44 pixels de área clicável, com pelo menos 8 pixels entre alvos vizinhos, sem aumentar o desenho dos ícones. 5. Corrija os campos do formulário: type, inputmode e autocomplete corretos por campo, com type=text e inputmode=numeric em CPF, CEP e cartão. 6. Acrescente srcset e sizes em toda imagem servida direto por , com o sizes descrevendo o layout real desta tela. Critérios de aceite, todos conferíveis na tela: - Em 390 px de largura, rolando a página inteira, não aparece barra de rolagem horizontal em nenhum ponto. - Com o teclado aberto, o campo em foco continua visível e o botão de enviar é alcançável. - Na aba de rede, com limitação de rede móvel, nenhuma imagem baixada tem mais que o dobro da largura em que ela aparece na tela. - Nenhum elemento fixo encosta na barra de gestos em aparelho com recorte. Se alguma correção depender de medir em aparelho real, diga isso em vez de afirmar que passou.