Como criar o efeito de texto do landonorris?
Inspirado no site do piloto Lando Norris, criei esse efeito de texto com animação ao hover que dá um efeito de profundidade muito interessante. landonorris.com
- E
- F
- E
- I
- T
- O
- I
- N
- S
- A
- N
- O
![]()
A Abordagem Manual vs Escalável
Sempre que você encontrar um padrões repetitivos no código, o ideal é sempre iterar sobre...
Neste caso, transformar hardcode em funções reutilizáveis economiza tempo, reduz erros e torna o código muito mais fácil de dar manutenção.
Hard Codar (não recomendada)
Você poderia fazer isso manualmente, colocando cada span na mão:
<li> <div> <span style="--time:1">B</span> <span style="--time:2">R</span> <span style="--time:3">U</span> <span style="--time:4">N</span> <span style="--time:5">O</span> </div> <div> <span style="--time:1">B</span> <span style="--time:2">R</span> <span style="--time:3">U</span> <span style="--time:4">N</span> <span style="--time:5">O</span> </div> </li>
Mas imagine fazer isso para cada palavra? Seria insano em 2025!
Solução Escalável (recomendada)
Por isso criei duas funções JavaScript que automatizam todo o processo:
// Transforma texto em spans com delay incremental const getChar = t => t.split('').map((t,i) => `<span style="--time:${i+1}">${t}</span>` ).join(''); // Duplica o texto para criar o efeito de camadas const groupChars = t => `<div>${getChar(t)}</div><div>${getChar(t)}</div>`; // Aplica em todos os <li> automaticamente document.querySelectorAll('li').forEach(li => li.innerHTML = groupChars(li.innerText) );
Agora basta escrever o HTML simples:
<ul> <li>BRUNO</li> <li>FRANCISCO</li> <li>CARDOSO</li> </ul>
E o JavaScript cuida do resto! E com o avanço dos browsers não será mais necessário adicionar a variavel --time nos spans programaticamente, a nova função do css sibling-index() (disponível apenas nos chrome/edge) retornará o indice de cada span e podemos usar como tempo de transição.
li { transition:calc(sibling-index() * .1s) ease-in-out all; }
Como Funciona
1. A Estrutura HTML
<ul class="text-3xl font-bold flex flex-col gap-2"> <li>BRUNO</li> <li>FRANCISCO</li> </ul>
2. O CSS com Custom Properties
li { position: relative; overflow: hidden; max-height: 2rem; /* 32px, altura de uma linha */ } /* Segunda camada fica desbotada */ li div:nth-child(2) span { opacity: 0.3; } /* Cada span tem transição baseada em sua posição */ li span { transition: calc(var(--time) * 0.1s) ease-in-out; display: inline-block; } /* Animação no hover */ li:hover span { translate: 0 -100%; opacity: 1 !important; }
3. O JavaScript que Monta Tudo
A mágica acontece em 3 etapas:
Etapa 1: getChar() divide o texto e adiciona custom property
"BRUNO" → '<span style="--time:1">B</span>' + '<span style="--time:2">R</span>' + '<span style="--time:3">U</span>' + '<span style="--time:4">N</span>' + '<span style="--time:5">O</span>'
Etapa 2: groupChars() duplica em duas camadas
'<div>BRUNO</div><div>BRUNO</div>'
Etapa 3: Aplica em todos os <li>
document.querySelectorAll('li').forEach(li => li.innerHTML = groupChars(li.innerText) );
Customizações Possíveis
Ajustar velocidade da animação:
/* Mais rápido */ transition: calc(var(--time) * 0.05s) ease-in-out; /* Mais lento */ transition: calc(var(--time) * 0.2s) ease-in-out;
Mudar direção:
/* Para cima (padrão) */ translate: 0 -100%; /* Para baixo */ translate: 0 100%; /* Para direita */ translate: 100% 0;
Adicionar bounce:
transition: calc(var(--time) * 0.1s) cubic-bezier(0.68, -0.55, 0.265, 1.55);
Resultado Final
Com apenas 3 linhas de JavaScript, criamos um efeito profissional e totalmente escalável!
HTML simples:
<li>BRUNO</li>
Vira automaticamente:
<li> <div> <span style="--time:1">B</span> <span style="--time:2">R</span> <span style="--time:3">U</span> <span style="--time:4">N</span> <span style="--time:5">O</span> </div> <div> <span style="--time:1">B</span> <span style="--time:2">R</span> <span style="--time:3">U</span> <span style="--time:4">N</span> <span style="--time:5">O</span> </div> </li>