É fácil desenhar uma interface quando tudo dá certo.
Os dados carregam.
O usuário tem permissão.
O texto cabe no espaço previsto.
A conexão está estável.
Nenhuma requisição falha.
Nesse cenário, praticamente qualquer interface bem construída consegue parecer boa.
O problema é que produtos reais não vivem apenas nesse cenário.
Eles carregam.
Falham.
Ficam sem dados.
Recebem conteúdos inesperados.
São usados em telas menores.
Precisam explicar por que determinada ação não pode ser realizada.
E é justamente quando o cenário ideal deixa de existir que boa parte das decisões de design começa a aparecer.
Uma interface bonita é importante.
Mas design de produto não termina nela.
O cenário perfeito engana
Quando estamos criando uma nova tela, normalmente começamos pelo caminho principal.
Existe um título.
Uma descrição.
Algumas informações.
Um botão.
Talvez uma tabela, um formulário ou um conjunto de cards.
Os dados utilizados na composição geralmente são bons o suficiente para representar aquilo que imaginamos.
Tudo está no lugar.
Isso é necessário para estruturar a experiência, mas cria um problema: começamos a avaliar o produto a partir de um estado que provavelmente representa apenas uma parte do uso real.
Uma tabela com dez registros pode funcionar perfeitamente.
Mas e quando existem zero?
E quando existem dez mil?
Um nome de usuário curto pode encaixar muito bem em um componente.
Mas e quando ele tem cinquenta caracteres?
Um formulário parece simples quando todos os campos são preenchidos corretamente.
Mas o que acontece quando três deles apresentam erros ao mesmo tempo?
O layout continua funcionando.
O produto talvez não.
Estados também são design
Durante muito tempo, era comum tratar estados como detalhes de implementação.
O designer entregava a tela.
Depois, durante o desenvolvimento, alguém percebia que precisava de um loading.
Depois aparecia a necessidade de uma mensagem de erro.
Depois um estado vazio.
Depois uma confirmação.
Cada situação era resolvida conforme surgia.
O resultado normalmente funcionava, mas nem sempre parecia fazer parte do mesmo produto.
Isso acontece porque esses estados não são apenas detalhes técnicos.
Eles fazem parte da experiência.
Um loading precisa comunicar que algo está acontecendo.
Um estado vazio precisa explicar por que nada apareceu e, em muitos casos, ajudar o usuário a entender qual é o próximo passo.
Uma mensagem de erro precisa fazer mais do que informar que alguma coisa deu errado.
Ela precisa ajudar alguém a se recuperar daquele erro.
Quando essas situações não são consideradas durante o design, a interface tende a funcionar bem justamente quando menos precisa ajudar.
O erro é parte do fluxo
Existe uma diferença importante entre desenhar para evitar erros e desenhar sabendo que erros acontecerão.
É claro que uma boa interface deve reduzir a possibilidade de erro.
Podemos validar informações antes do envio.
Desabilitar ações impossíveis.
Adicionar contexto.
Tornar determinadas escolhas mais claras.
Mas eliminar completamente falhas não é uma expectativa realista.
Usuários cometem erros.
Serviços falham.
Conexões caem.
Dados chegam incompletos.
Permissões mudam.
Uma API pode responder de uma maneira que a interface não esperava.
A pergunta de design, então, não é apenas:
Como fazemos isso funcionar?
Também é:
O que acontece quando isso não funciona?
Imagine um formulário de pagamento.
Existe uma diferença enorme entre mostrar:
Erro ao processar pagamento.
e explicar que o cartão foi recusado e que o usuário pode revisar os dados ou tentar outra forma de pagamento.
Tecnicamente, as duas mensagens representam uma falha.
Do ponto de vista da experiência, são produtos completamente diferentes.
Loading não deveria ser apenas um spinner
Algo parecido acontece com carregamento.
O spinner virou uma espécie de solução automática.
Existe uma requisição acontecendo?
Colocamos um spinner.
Só que o problema que precisamos resolver não é indicar que JavaScript está esperando uma resposta.
É ajudar o usuário a entender o estado atual do sistema.
Dependendo do contexto, isso pode significar skeletons.
Pode significar manter o conteúdo anterior enquanto novos dados são carregados.
Pode significar feedback otimista.
Pode significar uma mensagem dizendo que determinada operação demora alguns segundos.
Pode até significar não mostrar nenhum indicador perceptível porque a transição acontece rápido o suficiente.
A decisão depende do que está acontecendo.
Carregamento é uma questão técnica.
Mas a forma como ele é percebido é uma questão de experiência.
O vazio também precisa dizer alguma coisa
Estados vazios são outro exemplo interessante.
Uma tela sem conteúdo pode significar muitas coisas.
Talvez o usuário ainda não tenha criado nada.
Talvez uma busca não tenha encontrado resultados.
Talvez um filtro esteja escondendo tudo.
Talvez o usuário não tenha acesso àquele conteúdo.
Talvez algo tenha falhado silenciosamente.
Visualmente, todos esses estados podem parecer semelhantes:
nenhum item na tela.
Mas eles exigem respostas completamente diferentes.
Se é o primeiro acesso, talvez faça sentido ensinar.
Se a busca não encontrou nada, talvez seja útil sugerir uma alteração.
Se existe um filtro ativo, talvez devamos deixá-lo evidente.
Se o usuário não possui permissão, a interface precisa explicar essa limitação.
Design não é apenas decidir como preencher espaço.
Às vezes, é decidir o que fazer quando não existe nada para colocar nele.
Responsividade não é encaixar a mesma tela em menos espaço
Outro ponto comum aparece quando saímos do tamanho utilizado durante o design.
É relativamente fácil construir uma interface coerente quando sabemos exatamente quanto espaço existe.
O problema começa quando esse espaço muda.
Responsividade costuma ser tratada como um exercício de reorganização:
três colunas viram duas.
Duas viram uma.
O menu desaparece atrás de um botão.
Funciona.
Mas nem sempre isso é suficiente.
Uma tela menor também altera prioridade.
Talvez determinadas informações secundárias possam desaparecer.
Talvez uma tabela deixe de ser a melhor representação.
Talvez uma ação importante precise mudar de posição.
Talvez um fluxo que funciona bem lado a lado precise virar uma sequência.
O objetivo não deveria ser preservar o layout original a qualquer custo.
Deveria ser preservar a intenção da experiência.
Isso exige mais do que CSS.
Exige decisão.
Conteúdo real também testa o design
Existe outro tipo de realidade que costuma aparecer somente quando a aplicação começa a receber conteúdo verdadeiro.
Textos variam.
Nomes variam.
Imagens variam.
Valores variam.
Idiomas variam.
E a interface precisa sobreviver a isso.
Uma composição que depende de títulos com exatamente duas linhas pode funcionar perfeitamente no Figma e quebrar na primeira semana em produção.
Um botão com “Salvar” talvez fique ótimo.
O mesmo componente com “Salvar e continuar configuração” já exige outra análise.
Uma lista com nomes fictícios cuidadosamente escolhidos dificilmente representa toda a variedade que aparecerá depois.
Por isso, trabalhar com conteúdo real — ou pelo menos com conteúdo suficientemente imprevisível — muda a qualidade das decisões.
O design deixa de ser testado pelo cenário que criamos para ele.
Passa a ser testado pelo sistema que precisa sustentar.
Acessibilidade não deveria entrar no final
Algo semelhante acontece com acessibilidade.
Quando tratada como revisão final, ela frequentemente vira correção.
Adicionar contraste.
Ajustar labels.
Corrigir foco.
Adicionar atributos.
Revisar navegação por teclado.
Tudo isso é importante.
Mas alguns problemas não surgem na implementação.
Surgem na própria decisão de interação.
Um comportamento que depende exclusivamente de hover já começa com uma limitação.
Uma informação transmitida apenas por cor também.
Uma interação visualmente interessante, mas impossível de navegar por teclado, não se torna acessível apenas adicionando alguns atributos depois.
Acessibilidade afeta estrutura.
Hierarquia.
Conteúdo.
Interação.
Feedback.
Por isso, quanto mais cedo ela participa das decisões, menos precisa ser tratada como reparo.
Design também é decidir comportamento
Existe uma tendência natural de associar design ao que conseguimos ver.
Cores.
Tipografia.
Espaçamento.
Componentes.
Layout.
Tudo isso importa.
Mas produtos digitais também são comportamento.
O que acontece depois que alguém clica?
A interface responde imediatamente?
Existe confirmação?
A ação pode ser desfeita?
Precisamos perguntar antes de excluir?
O botão permanece disponível enquanto a requisição acontece?
O que acontece se o usuário clicar duas vezes?
Para onde ele vai depois de concluir o fluxo?
Nenhuma dessas decisões existe apenas no plano visual.
Elas vivem na relação entre design, frontend, backend, produto e conteúdo.
Talvez por isso algumas das melhores discussões sobre interface não sejam sobre pixels.
São sobre comportamento.
Não significa projetar todas as possibilidades
Existe, claro, um limite.
Tentar mapear antecipadamente cada combinação possível de estados pode transformar o processo em uma enorme tentativa de prever o futuro.
Não é esse o objetivo.
Produtos evoluem.
Situações inesperadas vão aparecer.
Algumas decisões só poderão ser tomadas depois de observar uso real.
A questão não é desenhar centenas de telas antes que uma linha de código seja escrita.
É reconhecer quais estados fazem parte da natureza daquele fluxo.
Se buscamos dados, existe carregamento.
Se uma requisição pode falhar, existe erro.
Se uma coleção pode estar vazia, existe ausência.
Se usuários têm permissões diferentes, existem estados de acesso.
Se uma ação altera algo importante, provavelmente precisamos pensar em feedback.
São consequências previsíveis daquilo que estamos construindo.
Ignorá-las não reduz a complexidade.
Apenas transfere a decisão para mais tarde.
E, normalmente, para alguém que estará tentando resolver o problema enquanto implementa.
Design como parte do sistema
Quanto mais trabalhamos em produtos reais, menos útil fica pensar em design como uma etapa isolada.
Primeiro alguém desenha.
Depois alguém implementa.
Depois alguém escreve o conteúdo.
Depois alguém testa.
Na prática, essas fronteiras são muito menos claras.
Uma decisão de backend pode limitar determinado comportamento da interface.
Uma escolha de copy pode mudar o tamanho de um componente.
Um requisito de acessibilidade pode alterar uma interação.
Uma restrição de performance pode exigir outra estratégia visual.
Um caso inesperado encontrado durante o desenvolvimento pode revelar que o fluxo original estava incompleto.
O produto melhora quando essas áreas conseguem conversar.
Não porque todos precisam fazer o trabalho uns dos outros.
Mas porque aquilo que estamos construindo é o mesmo sistema.
Indo além da criação
Uma interface bem resolvida no cenário ideal continua sendo importante.
Ela estabelece hierarquia.
Cria consistência.
Facilita o entendimento.
Define a identidade do produto.
Mas ela não representa sozinha a experiência inteira.
A experiência também está no momento em que algo demora.
Quando algo falha.
Quando não existe conteúdo.
Quando o usuário não pode continuar.
Quando a tela fica menor.
Quando o conteúdo foge do que imaginávamos.
Quando alguém utiliza a aplicação de uma forma diferente da nossa.
É nesses momentos que o design deixa de ser apenas aquilo que desenhamos.
E passa a ser aquilo que o produto consegue sustentar.
Uma interface bonita mostra como o produto deveria funcionar.
Um bom design também considera o que acontece quando a realidade não colabora.
Share on:
No spam. Only content worth opening.