stamatios
← Voltar ao feed
Ícones grudam como ímãs na primeira linha de texto com quebra, técnica CSS de alinhamento de listas
Dev & Engenharia

Alinhamento de ícones em listas se resolve com lh e translateY

resumo de ~3 min

O problema do alinhamento de ícones em listas

Ahmad Shadeed, design engineer, descreve um padrão comum de design que costuma ser negligenciado: listas de itens com ícones. Quando o texto ocupa uma linha, o ícone centralizado fica correto; quando o texto quebra em várias linhas, o ícone permanece centralizado verticalmente e o resultado fica visualmente estranho. O autor apresenta duas soluções, dependendo de como o ícone está no HTML: como elemento (como <svg> ou <img>) ou via pseudo-elemento com imagem de fundo.

Ícone como elemento no markup

A estrutura típica usa flexbox no item da lista, com display: flex, align-items: center e um gap. Com texto em uma linha, o resultado é aceitável. Quando a largura do contêiner diminui e o texto quebra, o ícone fica centralizado em relação a todo o bloco de texto - comportamento indesejado.

A primeira tentativa do autor foi trocar align-items: center por start. Isso gera outro problema: a altura do elemento de texto inclui espaço vazio acima e abaixo vindos da própria fonte (relacionados ao line-height), então o ícone alinha ao topo do contêiner, não à primeira linha. Empurrar o ícone com um valor fixo, como transform: translateY(3px), funciona, mas o autor testou variando três fatores - tamanho do ícone, tamanho da fonte e largura do contêiner - e mostrou que um valor fixo quebra quando qualquer um deles muda.

A solução com a unidade lh

A solução torna o deslocamento relativo ao line-height e ao tamanho conhecido do ícone. O cálculo usa calc((1lh - var(--size)) / 2) aplicado a translateY, em que o tamanho do ícone é definido via JavaScript. Com isso, alterar qualquer um dos três fatores mantém o alinhamento correto. O autor nota que, em alguns casos, o offset pode ficar negativo - por exemplo, quando o ícone é de 24px e a fonte de 17px.

Ícone como pseudo-elemento

No segundo cenário, o ícone é um pseudo-elemento ::before com uma imagem SVG embutida em data URI. A implementação inicial aparenta funcionar, mas aumentar o tamanho da fonte corta o ícone, porque falta limitar o tamanho do fundo - resolvido com background-size: contain.

Ao aumentar mais a fonte, a largura do ícone encolhe, já que itens flexíveis encolhem por padrão; a correção é flex-shrink: 0. Com isso, aumentar a fonte não altera mais o ícone, mas falta lidar com o alinhamento quando tamanho do ícone, da fonte e a largura do contêiner mudam.

Como o item da lista é um contêiner flexbox e os itens se esticam verticalmente por padrão, o ícone não estica porque tem altura fixa. Definir height: auto permite o esticamento, mas cria um novo problema: com fonte maior, o ícone fica quase quadrado; com fonte menor, vira um retângulo com espaço extra. Forçar aspect-ratio: 1 mantém o formato quadrado. Por fim, aplica-se a mesma técnica de deslocamento com calc((1lh - var(--size)) / 2) e translateY, centralizando o ícone em relação à primeira linha.

Conclusão

O autor resume as técnicas empregadas nas soluções: flexbox, aspect-ratio, a unidade lh, calc() e height: auto. Ele conta que resolveu o problema durante um projeto e decidiu compartilhar. O artigo também menciona seu curso de layouts em CSS, o The Layout Maestro, e um mailing list com mais de 3.400 assinantes.