← Blog/Atualizado em 16 de outubro de 2026·8 min de leitura

Como otimizei SEO e performance do meu portfólio

As ferramentas que usei, o que cada uma apontou, como corrigi e um checklist para aplicar em qualquer site. Com os números de antes e depois.

Este portfólio é cheio de animação, som e efeito, exatamente o tipo de site que costuma ir mal em performance. Então, antes de opinar, medi. Este post é o diário dessa otimização: quais ferramentas usei, o que cada uma encontrou, o que mudei e quanto melhorou.

No fim tem um checklist para aplicar em qualquer projeto. Eu mesmo vou usar nos meus outros apps.

Antes e depois

Medições do PageSpeed Insights na home, no celular. "Antes" é o primeiro deploy (15/10/2026), "depois" é o domínio próprio no dia seguinte, com as correções deste post.

MétricaAntesDepois
Performance8284
Acessibilidade9296 → 100*
Boas práticas96100
SEO100100
Total Blocking Time80 ms50 ms
Speed Index7,8 s6,4 s
Largest Contentful Paint3,6 s3,5 s

* O 96 tinha um problema de contraste que corrigi depois dessa medição; no Lighthouse local, com a correção, a acessibilidade chega a 100.

As ferramentas

FerramentaO que medePrecisa de login?
LighthouseCarregamento, acessibilidade, boas práticas e SEO, rodando no seu computadorNão
PageSpeed InsightsO mesmo Lighthouse, rodando nos servidores do Google, mais dados de usuários reais quando o site tem tráfegoNão
Chrome DevToolsFluidez durante o uso: FPS, frames lentos, tarefas longasNão
Schema Markup ValidatorSe os dados estruturados (JSON-LD) estão corretosNão
Rich Results TestSe o Google consegue gerar resultados ricos com esses dadosSim, conta Google
Google Search ConsoleIndexação, buscas que trazem gente ao site, erros de rastreamentoSim, e verificar o domínio

Uma regra que aprendi: rode o Lighthouse mais de uma vez. No meu desktop, três rodadas seguidas deram 95, 83 e 85. Use a mediana, não o melhor número.

O que cada ferramenta encontrou

1. O preloader segurava a página

O preloader (aquele contador de 0 a 100) durava 1,6 s. Ele cobria o título principal, que é o maior elemento da tela, e o LCP passava de 3 segundos no celular. Baixei para 0,4 s.

O ganho no LCP foi pequeno (3,6 s para 3,5 s), e isso também é um aprendizado: o título entra com uma animação de revelação, e o navegador só conta o LCP quando ele aparece de verdade. O próximo passo é fazer o título já nascer visível e animar só o detalhe.

2. Um erro que só existia em produção

As boas práticas estavam em 96 por causa de um erro no console: erro de hidratação do React (#418). As datas dos posts eram formatadas no fuso do servidor (UTC) e no fuso do navegador (UTC−3), e uma data de meia-noite virava "12 de ago." num lado e "11 de ago." no outro.

No meu computador, servidor e navegador estavam no mesmo fuso, então o erro nunca aparecia. A correção foi formatar as datas sempre em UTC. Resultado: 100 em boas práticas.

3. Acessibilidade: o que o olho não vê

O Lighthouse apontou quatro problemas, nenhum visível a olho nu:

  • aria-label proibido: a biblioteca que divide o texto para animar (SplitText) colocava aria-label em parágrafos, o que só é permitido em títulos e alguns elementos.
  • Nome acessível diferente do texto visível: o link do logo dizia "Início" para leitores de tela, mas mostrava "Iago Gois".
  • Contraste de um atalho dentro do debugger.
  • Contraste dos botões: o laranja do tema Editorial com texto branco dava 4,0:1, e o mínimo é 4,5:1. Calculei o contraste de todos os temas: três combinações estavam abaixo. Escureci levemente dois tons e troquei a cor do texto no terceiro, sem mudar a cara de nenhum tema.

4. A página "pulava" no desktop

No desktop, o PageSpeed acusou CLS de 0,105 (o limite do "bom" é 0,1). O culpado parecia ser o efeito de granulado da tela, mas não era: durante o preloader a rolagem fica travada, sem barra; quando ela libera, a barra de rolagem aparece e a página fica 15 px mais estreita, e tudo se desloca. O granulado só levou a culpa por ser o maior elemento.

A correção é uma linha de CSS:

CSS
html {
  scrollbar-gutter: stable;
}

Ela reserva o espaço da barra desde o início. O mesmo problema derrubava um item da nova categoria Agentic Browsing do Lighthouse, que mede se o site é navegável por agentes de IA.

5. Fluidez: o que o Lighthouse não mede

Lighthouse só olha o carregamento. Num site animado, o que importa também é se a rolagem é suave. Escrevi um teste que abre o site no Chrome com tela de celular e CPU 4x mais lenta, rola até o fim e mede cada frame.

A primeira descoberta foi incômoda: o modo leve não aliviava nada. No tema Aurora ele era até mais lento que tudo ligado.

Para entender o porquê, gravei traces de performance no Chrome DevTools e desliguei um efeito por vez:

  • JavaScript não era o problema. Era só ~8% do tempo de CPU durante a rolagem, somando GSAP, React e o código do site.
  • O custo vinha de efeitos que nunca param: marquees (mesmo fora da tela), grain animado, reveal linha a linha e, no Aurora, o fundo com blur ao vivo e o desfoque de vidro nos cards. Enquanto algo se mexe, o navegador refaz estilo e camadas da página inteira a cada frame.
  • O modo leve mirava o alvo errado. Desligava cursor, magnetismo e tilt, que no celular já não rodam (precisam de mouse), e trocava o shader por um fundo com blur que não era mais barato.

O que mudou:

  • Marquees e loops infinitos pausam quando saem da tela, em todos os modos.
  • No modo leve: grain parado, fundo animado vira um gradiente fixo, sem desfoque de vidro e reveal por bloco em vez de por linha.

Resultado no celular simulado (FPS médio, mediana de 4 rodadas):

TemaCenárioAntesDepois
EditorialTudo ligado5968
EditorialModo leve5575
AuroraTudo ligado4548
AuroraModo leve3563
Os doisSem animação (referência)113113

No Aurora, os frames lentos (abaixo de 30 fps) no modo leve caíram de 23,5% para 2,2%. E agora o modo leve é, de fato, mais leve que tudo ligado.

Uma lição de método: intercale as rodadas. Rodando um cenário depois do outro, o mesmo teste deu 28 fps numa bateria e 57 na seguinte, só por variação da máquina. Alternando os cenários a cada rodada, os números ficaram estáveis, e a linha "sem animação", que não mudou de código, serve de controle.

SEO técnico

O básico, que todo site deveria ter:

  • Metadados por página: título e descrição próprios em cada página, projeto e post.
  • Canonical e hreflang: o site é bilíngue, e cada página diz qual é a versão em português e qual é a em inglês, para o Google mostrar a certa.
  • Sitemap e robots.txt gerados automaticamente.
  • Imagem de compartilhamento (OG) por idioma, para o link ficar bonito no LinkedIn.

Uma pegadinha do domínio: o www.iagogois.com.br redireciona para iagogois.com.br, mas por um momento o sitemap apontava para o www. O Google prefere a URL final, sem redirecionamento, então fixei o domínio principal no código.

Dados estruturados

São blocos invisíveis em JSON-LD que dizem às máquinas o que é a página: uma pessoa (Person), um site (WebSite), uma lista de projetos e cada post (BlogPosting).

O Schema Markup Validator encontrou os blocos com 0 erros e 0 avisos. O Rich Results Test faz uma checagem parecida do ponto de vista do Google, mas pede login com conta Google.

SEO para IAs

Cada vez mais gente pergunta para o ChatGPT, o Claude ou o Perplexity em vez de pesquisar no Google. Para aparecer nessas respostas, o site precisa ser fácil de ler por uma IA:

  • Conteúdo renderizado no servidor: o HTML já chega com todo o texto, sem depender de JavaScript.
  • llms.txt: um resumo em Markdown em /llms.txt, com quem sou, projetos e links, no formato que modelos de linguagem leem. Existe também a versão completa em /llms-full.txt.
  • robots.txt liberando os robôs de IA, como GPTBot, ClaudeBot e PerplexityBot.
  • Dados estruturados: os mesmos que ajudam o Google ajudam as IAs a entender quem é quem.

Na categoria Agentic Browsing do Lighthouse, o celular fez 3/3.

Search Console

O Google Search Console é onde o Google conta o que vê do seu site: quais páginas indexou, que buscas trouxeram visitas e o que deu erro. Para configurar:

  1. Entre no Search Console e adicione uma propriedade de domínio (iagogois.com.br). Ela cobre www, http e todas as páginas.
  2. O Google mostra um registro TXT. Crie esse registro no DNS do domínio (no meu caso, no Registro.br).
  3. Volte e clique em Verificar. Pode levar alguns minutos.
  4. Envie o sitemap: https://iagogois.com.br/sitemap.xml.

Os dados começam a aparecer em alguns dias. Volto aqui com os números quando tiver.

Checklist para qualquer site

  • Rodar o Lighthouse 3 vezes e usar a mediana
  • Rodar o PageSpeed Insights no celular e no desktop
  • Olhar o console do navegador em produção, não só no local
  • Testar com o servidor e o navegador em fusos diferentes
  • Conferir contraste de texto sobre a cor de destaque (mínimo 4,5:1)
  • Usar scrollbar-gutter: stable se a página trava a rolagem em algum momento
  • Medir a fluidez da rolagem, não só o carregamento
  • Pausar animações infinitas fora da tela
  • Título, descrição e canonical em cada página
  • hreflang se o site tiver mais de um idioma
  • Sitemap e robots.txt
  • Dados estruturados validados no Schema Markup Validator
  • llms.txt e robots.txt liberando os robôs de IA
  • Search Console com propriedade de domínio e sitemap enviado

O que ainda falta

  • LCP no celular (3,5 s): fazer o título principal aparecer sem esperar a animação.
  • JavaScript inicial no celular: é o maior custo de tempo de bloqueio.
  • Dados reais de visitantes: os números acima são de laboratório. Com tráfego, o PageSpeed passa a mostrar a experiência de quem visita de verdade.
--fps