O que wireframe faz?
Crie wireframes de média fidelidade (mid-fi) como um único arquivo HTML autossuficiente. Múltiplas telas lado a lado, responsivas, em escala de cinza com uma cor de destaque, com cópia real.
Princípios fundamentais
Mid-fi significa:
- Uma paleta em escala de cinza (veja os tokens abaixo), mais uma cor de destaque (
--accent) para ações primárias e estados ativos. Isso torna a ação principal visível rapidamente; nenhuma outra cor é utilizada. - Rótulos, títulos e cabeçalhos reais, sem "Lorem ipsum". Escreva a cópia no idioma que os usuários finais do produto verão; se isso não estiver claro, use o idioma da solicitação. Dessa forma, o wireframe pode ser mostrado às partes interessadas como está, mesmo quando a conversa acontece em outro idioma.
- Blocos placeholder para imagens (sem ativos reais)
- Ícones de linha Lucide onde um ícone carrega significado (veja Ícones)
- Estados de hover em tudo que for clicável (veja Estados de hover)
- Uma hierarquia tipográfica clara
- Sem decoração, sem sombras, apenas bordas sutis
Nunca:
- Cores de marca, ou qualquer cor além do destaque
- Imagens reais, fotos, logotipos ou ilustrações
- Emojis ou símbolos de texto como ícones (☰, ×, ›): use Lucide
- Animações (uma
transitioncurta ao passar o mouse é aceitável) - Explicações dentro do próprio wireframe (anotações vão fora dele)
Apoie o processo criativo
Um wireframe é uma ferramenta de pensamento: ajuda o usuário a esclarecer o quê e por quê, raciocinando em voz alta, duvidando e iterando. Seu trabalho é apoiar esse processo, não assumi-lo. Isso funciona nos dois sentidos: não construa apenas sem nenhuma discussão e não enterre o usuário em conversa antes que algo apareça na tela. A tela é uma peça de conversação, não uma entrega.
Por tipo de entrada
- Nova solicitação: abra sua resposta com um pequeno bloco de debate: as 2-3 escolhas mais importantes, cada uma com suas opções e sua preferência com uma justificativa. Inclua interação, não apenas layout: o que acontece ao tocar ou clicar, onde o feedback aparece, o que pode ser desfeito, modal ou página separada, inline ou uma etapa extra. Em seguida, construa sua opção preferida, para que haja algo concreto para reagir. Alguns tópicos, não uma redação. (Solicitação vaga com escopo complexo? Faça a única pergunta da Intenção de otimização primeiro.)
- Solicitação exploratória ("Estou em dúvida entre...", "o que funcionaria para...", pensando em voz alta): apenas debata. Apresente as opções com suas vantagens e desvantagens e sua preferência, depois pergunte se deve construir uma delas, e qual.
- Entrada de acompanhamento: responda ao conteúdo primeiro: pense junto, adicione a ele, exponha uma fraqueza ou uma alternativa. Altere o wireframe apenas quando algo tiver sido decidido, não a cada pensamento passageiro. Não tem certeza se é debate ou decisão? Pergunte rapidamente: "Devo aplicar isso, ou pensar primeiro?"
Como debater
- Reaja em voz alta. Se um padrão pode não funcionar neste contexto (por exemplo, uma lista curta quando há apenas 2 itens), diga isso em vez de construí-lo cegamente.
- Ofereça direções, não decisões fechadas. Quando uma escolha é genuinamente aberta, mostre A e B lado a lado no wireframe em vez de apenas descrevê-los, e diga qual você prefere.
- Itere em pequenos passos. Espere mudanças por elemento. Construa sobre o que o usuário seleciona ou aponta.
- Não force uma decisão. O objetivo é clareza; a escolha pode vir depois.
- Mantenha leve. Uma linha por opção, um punhado de tópicos no total e no máximo uma pergunta focada. O wireframe fala por si, então não explique o que está nele; mencione apenas o que o usuário não pode ver, como uma suposição ou o que acontece ao clicar.
Princípios de UX
- Questione o conceito, não apenas o layout. Continue verificando se a função subjacente realmente se sustenta e desafie-a, não apenas "como isso se parece".
- Não reivindique um status que o sistema não pode saber. Baseie a UI nos dados disponíveis. Se algo não pode ser sabido, mostre a ação em vez de um status, ou deixe o usuário marcá-lo.
- Combine a fidelidade do conteúdo ao propósito da tela. Se o ponto é estrutura ou navegação, torne o conteúdo de baixa fidelidade (linhas placeholder) para que o foco permaneça no assunto.
- Wireframe os estados-chave lado a lado. Logado/deslogado, vazio/preenchido, aberto/fechado: isso torna as decisões reais visíveis.
- Traduza a navegação deliberadamente para telas menores. Mantenha uma âncora persistente para que a transição não seja brusca; priorize e agrupe em vez de mostrar tudo. Uma estrutura de navegação, várias cascas, uma fonte.
Entrega
- Mantenha cada wireframe como um arquivo HTML autossuficiente. Nenhum arquivo JS/CSS separado ao lado dele: as prévias geralmente renderizam o arquivo sozinho, sem arquivos irmãos. Os dois links CDN no modelo base (IBM Plex Sans via Google Fonts, Lucide via jsDelivr) são a exceção; eles carregam bem nas prévias. Quer reutilização? Embuta um modelo mestre e sincronize as cópias.
- Para um grande conjunto de telas, adicione um alternador de tela fixo (por exemplo, um menu suspenso) para pular entre elas.
- Para um conceito que abrange várias partes do produto, construa um site conceito (veja abaixo).
Site conceito
Quando um conceito cobre várias partes de um produto (onboarding, busca, conta...) e o usuário quer mostrar ou revisar tudo como um todo, construa um site conceito: uma página por parte, conectadas pela mesma barra de menu. As partes interessadas têm um lugar para percorrer todo o conceito, e você pode iterar em uma parte sem tocar no resto.
- Barra de menu no topo de cada página, na tela, acima dos quadros. Esquerda: o nome do conceito com um ícone
infocujo tooltip contém a versão, data e uma explicação de uma linha. Em seguida, um divisor e um link por parte. A página atual recebearia-current="page"e é estilizada--text-primary/600; as demais--text-secondary. Quando os links não cabem, a barra rola horizontalmente em vez de quebrar. Para um conceito grande (mais de cerca de 15 telas), adicione um menu suspenso "Ir para tela" na extremidade direita da barra que pula para qualquer tela em qualquer página; para conceitos menores, o menu é suficiente. - Arquitetura da Informação (IA) primeiro. O primeiro link é uma página de IA: a estrutura do produto com um link para cada parte. É também a página de entrada.
- Cada página de parte é um wireframe normal: quadros lado a lado, rótulos de quadro, a tela pontilhada.
- Arquivos separados quando forem abertos juntos. Se você puder escrever uma pasta que o usuário abre em um navegador ou hospeda (trabalhando localmente, em um repositório), faça
index.htmlpara a IA mais um arquivo por parte com um slug curto (onboarding.html), vinculado relativamente. - Um arquivo quando for pré-visualizado sozinho. Um artefato individual ou prévia de chat renderiza um arquivo sozinho, então links para outros arquivos quebram lá. Coloque todas as partes em um arquivo como seções, alternadas pelo menu via links
#hash(#onboarding). - Mantenha o menu idêntico em todos os lugares. Embuta-o em cada arquivo a partir de uma cópia mestre, para que cada página ainda funcione sozinha. Quando uma parte é adicionada, renomeada ou removida, atualize o menu em todos os arquivos de uma vez.
Tokens de design
:root {
--bg: #F5F5F5; /* fundo da página */
--surface: #FFFFFF; /* cartões, painéis */
--border: #D1D1D1; /* bordas */
--muted: #E8E8E8; /* blocos placeholder */
--text-primary: #1A1A1A;
--text-secondary: #595959; /* meta, placeholders, rótulos em blocos de imagem */
--text-disabled: #AAAAAA; /* apenas controles desabilitados */
--accent: #1560D0; /* a única cor: ações primárias, estados ativos */
--accent-hover: #1250B0;
--hover-bg: #F0F0F0; /* hover em elementos claros ou transparentes */
--border-hover: #AAAAAA; /* hover em elementos com borda */
--font: 'IBM Plex Sans', system-ui, sans-serif;
}
Estes tokens são ajustados para WCAG AA (4.5:1): --text-primary e --text-secondary passam em todas as cores de superfície aqui (--surface, --bg, --hover-bg, --muted, --border); --accent como texto passa em todas exceto --border; branco passa em --accent. A acessibilidade começa no wireframe, então mantenha assim: não adicione cinzas mais claros para texto. A única exceção é --text-disabled (2.3:1): use-o apenas para controles desabilitados, que o WCAG isenta, nunca para texto legível como metadados.
Estrutura HTML
Modelo base
Defina lang para o idioma da cópia.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wireframe: [assunto]</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&display=swap" rel="stylesheet">
<style>
/* tokens */
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; -webkit-font-smoothing: antialiased; }
button, input, select, textarea { font: inherit; } /* controles de formulário não herdam a fonte por padrão */
/* layout + componentes */
</style>
</head>
<body>
<div class="wireframe-canvas">
<div class="frame-row">
<!-- quadros aqui -->
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/lucide@1/dist/umd/lucide.min.js"></script>
<script>lucide.createIcons();</script>
</body>
</html>
Layout para múltiplos quadros
Esta tela é o que faz a saída ser lida como um wireframe rapidamente, então use-a como está.
.wireframe-canvas {
background-color: var(--bg);
background-image: radial-gradient(circle, #C8C8C8 1px, transparent 1px);
background-size: 20px 20px;
padding: 40px;
min-height: 100vh;
font-family: var(--font);
}
.frame-row {
display: flex;
gap: 32px;
align-items: flex-start;
flex-wrap: wrap;
}
.frame {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
flex-shrink: 0;
}
/* Largura por dispositivo */
.frame.mobile { width: 375px; }
.frame.tablet { width: 768px; }
.frame.desktop { width: 1280px; }
.frame.auto { width: 100%; max-width: 1280px; }
Rótulo do quadro (acima de cada tela)
<div class="frame-label">Tela 1: [nome]</div>
<div class="frame mobile">
<!-- conteúdo -->
</div>
.frame-label {
font-size: 11px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text-secondary);
margin-bottom: 8px;
}
Componentes
Escreva o HTML e CSS dos componentes você mesmo, mas mantenha estes valores para que os wireframes pareçam consistentes entre as sessões. Dê aos botões e inputs um min-height com inline-flex centralizando em vez de depender de padding: apenas padding acaba ficando um pouco abaixo de 40px, e 40px é o alvo de clique mínimo.
| Componente | Especificação |
|---|---|
| Botão primário | Preenchimento --accent, texto branco, 14px/600, min-height: 40px, padding 0 20px, raio 6px |
| Botão secundário | Transparente, texto --accent, borda de 1.5px --accent, caso contrário, como primário |
| Botão de texto / ação inline | "Editar", "Definir status", "Alterar": texto --accent, 14px/500, sem borda. Ainda um alvo de 40px: min-height: 40px com inline-flex, ou padding com uma margem negativa igual quando está dentro de uma linha |
| Input | Rótulo acima (13px/500, --text-primary, gap de 4px). Campo: 1px --border, raio 6px, min-height: 40px, padding 0 12px, 14px, texto placeholder em --text-secondary |
| Placeholder de imagem | Bloco --muted com aspect-ratio fixo, rótulo centralizado em --text-secondary 13px nomeando conteúdo e proporção ("Foto do produto 16:9") |
| Cartão | --surface, 1px --border, raio 8px, overflow: hidden. Corpo padding 16px, gap 4px: overline 11px uppercase --text-secondary, título 15px/600, meta 12px --text-secondary |
| Tag | 12px/500, padding 2px 8px, raio 4px (menor que seu cartão), fundo --muted, texto --text-secondary |
| Barra de navegação mobile | Padding 12px 16px, borda inferior. Texto do logotipo 16px/600 à esquerda, Lucide menu em um botão 40×40 à direita, com aria-label |
| Barra de navegação desktop | Padding 16px 32px, borda inferior. Logotipo, links (14px, --text-secondary, gap 24px, ativo --text-primary/500), botão primário à direita |
| Stepper | Círculos de 28px com números 13px/600, linha de conexão de 32px em --border. A fazer: --muted/--text-secondary. Ativo: --accent/branco. Concluído: --border/--text-secondary |
Precisa de um componente que não está listado? Derive-o desses valores (mesmos raios, escala de tipo e estados) em vez de inventar novos.
Intenção de otimização
Se a solicitação contiver uma direção ("menos etapas", "mais fácil de escanear", "menos carregado", "mais rápido de entender"), use-a como lente: escolha componentes, hierarquia e estrutura de cópia que reforcem essa direção.
Se a solicitação for vaga e o escopo for complexo (3+ telas ou um fluxo), faça uma pergunta focada: "O que você quer melhorar: visão geral, velocidade, confiança ou outra coisa?"
Não pergunte para telas únicas ou quando a intenção já estiver clara.
Abordagem por tipo de entrada
Tela ou fluxo descrito em palavras
- Identifique as telas na descrição (cada tela = um quadro)
- Determine o tipo de dispositivo (mobile para aplicativos quando não declarado, desktop para web)
- Coloque todos os quadros em um arquivo, lado a lado
- Use cópia real que se encaixe no contexto, no idioma dos usuários finais (veja Princípios fundamentais)
Número de quadros
- 1 tela: mostre na largura do dispositivo
- 2-4 telas: lado a lado em uma linha
- 5+ telas: duas linhas, ou role horizontalmente
Estados de hover
Sempre adicione-os. Wireframes devem ser clicáveis, e o hover mostra o que é interativo. Existem três padrões. Aplique-os às classes que você criar neste wireframe, não a uma lista fixa:
/* 1. Preenchido com destaque: botão primário, chip ativo ou aba, FAB */
.btn-primary:hover { background: var(--accent-hover); cursor: pointer; }
/* 2. Claro ou transparente: botão secundário, botão de ícone, item de lista */
.btn-secondary:hover,
.nav-menu:hover { background: var(--hover-bg); cursor: pointer; }
/* 3. Com borda: cartão clicável, chip, opção de escolha */
.card:hover { border-color: var(--border-hover); cursor: pointer; }
Todo elemento interativo recebe cursor: pointer. Elementos não interativos (texto, rótulos, placeholders, cartões que não são clicáveis, etc.) não recebem hover nem ponteiro.
Ícones
Use ícones de linha do Lucide. Eles são carregados via CDN (incluído no modelo base) e renderizados com <i data-lucide="search"></i>. O atributo data-lucide aceita o nome do ícone em kebab-case. Ícones úteis: search, chevron-left, chevron-right, x, menu, home, user, settings, plus, minus, check, arrow-left, arrow-right, info, more-horizontal, trash-2, mail, bell, calendar, clock, upload, download, camera, image, globe, lock, unlock, edit-3, copy, share-2, external-link, filter, list, grid, columns, maximize-2, minimize-2.
- Defina explicitamente
widtheheightno<i>quando o ícone estiver em um botão (ex.:<i data-lucide="menu" width="20" height="20"></i>). Em outros lugares, o tamanho padrão (24px) geralmente funciona. - Use
stroke="var(--accent)"para ícones em elementos interativos de destaque,stroke="var(--text-secondary)"para ações secundárias. - Ícones decorativos que não carregam significado (ex.: um ícone de calendário ao lado de uma data) têm
aria-hidden="true". - Ícones que são o único conteúdo de um link ou botão (ex.: o hambúrguer do menu) têm
aria-labelno botão earia-hidden="true"no ícone.
Exemplos
Tela única (mobile)
Wireframe de uma tela de login.
<div class="frame-label">Tela 1: Login</div>
<div class="frame mobile">
<div style="padding: 24px; display: flex; flex-direction: column; gap: 20px;">
<div style="font-size: 24px; font-weight: 600; color: var(--text-primary);">Entrar</div>
<div>
<label style="display: block; font-size: 13px; font-weight: 500; color: var(--text-primary); margin-bottom: 4px;">E-mail</label>
<input type="email" placeholder="[email protected]" style="width: 100%; padding: 0 12px; min-height: 40px; border: 1px solid var(--border); border-radius: 6px; font-size: 14px; color: var(--text-primary); background: var(--surface);">
</div>
<div>
<label style="display: block; font-size: 13px; font-weight: 500; color: var(--text-primary); margin-bottom: 4px;">Senha</label>
<input type="password" placeholder="••••••••" style="width: 100%; padding: 0 12px; min-height: 40px; border: 1px solid var(--border); border-radius: 6px; font-size: 14px; color: var(--text-primary); background: var(--surface);">
</div>
<button class="btn-primary" style="width: 100%; background: var(--accent); color: white; border: none; border-radius: 6px; min-height: 40px; font-size: 14px; font-weight: 600; padding: 0 20px; display: inline-flex; align-items: center; justify-content: center;">Entrar</button>
</div>
</div>