
🔧 JQuery: scroll suave para âncora ao navegar a partir de outra página
Adicionou uma âncora à página, colocou #section no URL e espera um scroll suave e agradável. O utilizador clica a partir de outra página, o navegador aplica o hash obedientemente... e salta abruptamente para o destino. Sem scroll. Apenas um salto instantâneo.
O problema é que os navegadores tratam o hash instantaneamente por defeito, antes de o DOM estar totalmente pronto e de os scripts terem oportunidade de intercetar o evento. Quando um utilizador chega através de um link externo, o seu handler de click nunca chega a disparar: não houve evento de clique, apenas uma navegação direta por URL.
Compilámos duas soluções jQuery testadas em cenários reais: um script básico para casos simples e uma versão avançada com tratamento de cliques, suporte para carregamento de página e prevenção de conflitos. Ambas foram testadas em projetos reais e funcionam com as versões atuais do jQuery.
💡 Visão geral rápida:
- Guarde o hash do URL numa variável temporária
- Limpe
location.hashpara que o navegador não salte abruptamente - Faça scroll até à âncora via
animate()com o deslocamento desejado - Restaure o hash para ter um URL correto na barra de endereço
Porque é que o scroll suave para âncoras é importante
Quando um visitante segue um link como site.com/page/#pricing, espera ver o bloco de preços, não o topo da página. Um salto abrupto é desorientador: o utilizador não percebe onde aterrou nem o que veio antes. O scroll suave fornece contexto: os olhos captam as secções intermédias e o cérebro mapeia o percurso da origem ao destino.
Com a propriedade nativa de CSS scroll-behavior: smooth, as coisas são simples: adicione-a à sua folha de estilos e o navegador faz scroll até à âncora automaticamente. Mas esta abordagem deixa de funcionar no momento em que precisa de um deslocamento personalizado para um cabeçalho fixo. Um deslocamento de 110 píxeis impede que o bloco deslize para debaixo do header e posiciona-o exatamente onde o utilizador espera. A solução jQuery dá-lhe esse controlo.
Há também a questão da compatibilidade entre navegadores. scroll-behavior: smooth não funciona no Internet Explorer (sim, esses projetos ainda existem), enquanto o método animate() do jQuery se comporta de forma idêntica em todo o lado.
Script básico: código mínimo, benefício máximo
A primeira opção é compacta, apenas 10 linhas. Resolve exatamente um problema: fazer scroll suave até uma âncora quando o utilizador chega de outra página ou através de um link direto com hash.
1 jQuery(document).ready(function ($) { 2 var myHash = location.hash; // save the hash 3 location.hash = ''; // clear it — browser stops jerking 4 if (myHash[1] != undefined) { // hash not empty? 5 $('html, body').animate( 6 { scrollTop: $(myHash).offset().top - 110 }, 7 700 // duration in milliseconds 8 ); 9 location.hash = myHash; // restore the hash 10 } 11 });
Explicação passo a passo, porque três linhas fazem magia, mas compreender a mecânica é importante:
var myHash = location.hash: lê o hash da barra de endereço (por exemplo,#pricing). Neste momento, o navegador ainda não fez scroll.location.hash = '': o truque principal. Limpar o hash faz com que o navegador perca o alvo para o salto instantâneo. Sem esta linha, o script «lutaria» contra o comportamento nativo do navegador e perderia.$(myHash).offset().top - 110: calcula a posição da âncora a partir do topo do documento e subtrai 110 píxeis. Este é o seu deslocamento para um cabeçalho fixo. Se o seu cabeçalho tiverposition: fixede 80px de altura, use 80 (ou 90 para dar alguma margem). Se não houver cabeçalho, remova completamente a subtração.$('html, body').animate(...): faz scroll suave durante 700 milissegundos. O seletor'html, body'não é um capricho: navegadores diferentes fazem scroll ou nohtmlou nobody, por isso especificamos ambos para fiabilidade.location.hash = myHash: restaura o hash. Agora a barra de endereço mostra novamente#pricinge a página já está confortavelmente estacionada no bloco de destino.
Insira o script no functions.php do seu tema, num ficheiro JS personalizado ou através de um plugin como Code Snippets. O requisito principal é que deve estar dentro de um bloco jQuery(document).ready().
Versão avançada: tratamento de cliques, carregamento de página e proteção contra conflitos
O script básico cobre a maioria dos cenários, mas por vezes location.hash = '' não funciona a tempo: o navegador salta antes de o hash ser limpo. Nesses casos, use a segunda versão. É mais pesada, mas mais fiável.
1 jQuery(document).ready(function () { 2 jQuery(window).bind('load', function () { 3 jQuery('a:not(.spu-clickable)[href*="#"]:not([href="#"])').click(function () { 4 if ( 5 location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') || 6 location.hostname == this.hostname 7 ) { 8 var target = jQuery(this.hash); 9 target = target.length ? target : jQuery('[name=' + this.hash.slice(1) + ']'); 10 if (target.length) { 11 jQuery('html, body').animate( 12 { scrollTop: target.offset().top - 37 }, 13 1000 14 ); 15 return false; 16 } 17 } 18 }); 19 }); 20 }); 21 22 jQuery(window).load(function () { 23 function goToByScroll(id) { 24 jQuery('html, body').animate( 25 { scrollTop: jQuery('#' + id).offset().top - 38 }, 26 1000 27 ); 28 } 29 if (window.location.hash != '') { 30 goToByScroll(window.location.hash.substr(1)); 31 } 32 });
Eis o que acontece, bloco a bloco:
Bloco um: um handler de clique para links de âncora internos. jQuery(window).bind('load', ...) garante que todos os elementos da página (incluindo imagens e iframes) são carregados antes de vincular o handler. O filtro a:not(.spu-clickable) exclui links já tratados por um plugin de popup (SPU, WordPress PopUp), prevenindo conflitos de animação. Adicione as suas próprias classes de exclusão seguindo o mesmo padrão.
Bloco dois: tratamento da navegação a partir de uma página externa. jQuery(window).load() dispara mais tarde do que document.ready e garante que todos os elementos, incluindo a âncora, estão no DOM. A função goToByScroll(id) faz exatamente o que o script básico faz, mas só é chamada depois de a janela carregar completamente. substr(1) remove o caractere # do hash.
Nota importante: jQuery(window).load() foi descontinuado desde o jQuery 3.0. Se o seu projeto usar uma versão atual do jQuery, substitua por:
1 jQuery(window).on('load', function () { 2 // code here 3 });
A sintaxe difere, mas o comportamento é idêntico.
Afinação: deslocamentos, seletores e armadilhas
O script funciona, mas cada layout é único. Eis três ajustes comuns que salvaram projetos reais.
Problema um: offset().top devolve coordenadas incorretas. Isto acontece quando elementos pai têm as propriedades CSS transform, filter ou will-change, que criam um novo contexto de posicionamento. O offset() calcula então em relação a esse contexto em vez do documento. Solução: use offset({top: -0}):
1 jQuery('html, body').animate( 2 { scrollTop: jQuery('#' + id).offset({ top: -0 }).top }, 3 1000 4 );
O parâmetro {top: -0} força o jQuery a recalcular a posição a partir dos limites do documento, ignorando contextos intermédios. Parece magia, mas funciona.
Problema dois: o seletor 'html, body' faz scroll no elemento errado. Em alguns temas, o contentor de scroll não é html nem body, mas um bloco específico, por exemplo, body.home para a página inicial ou .main-content para páginas internas. Identifique o seu contentor através das DevTools (separador Elements → procure por overflow: scroll ou overflow: auto) e substitua-o no seletor:
1 jQuery('body.home').animate( 2 { scrollTop: target.offset().top - 37 }, 3 1000 4 );
Problema três: o hash contém caracteres cirílicos ou especiais. location.hash devolve uma sequência codificada em URL em vez de uma string legível, e o seletor jQuery $(myHash) não encontrará o elemento. Solução: descodifique o hash com decodeURIComponent() antes de o usar no seletor.
Vídeo: exemplo ao vivo de scroll a partir de um link externo
Uma demonstração curta de John Smith: scroll suave para âncora via animate() do jQuery numa página real com cabeçalho fixo e navegação externa.
⁉️🤔 Perguntas frequentes
O script funciona na mesma página, mas não quando se navega a partir de outro URL. Porquê?
Porque o handler de
clicknunca dispara: não houve clique. O utilizador seguiu um link direto e o navegador processou o hash antes de o seu JS ser executado. A solução é a sequêncialocation.hash = ''+animate()+location.hash = myHash. Limpar o hash cancela o salto nativo, a animação faz scroll suave e restaurar o hash preserva o URL correto na barra de endereço.
Que deslocamento devo usar para um cabeçalho fixo?
A altura exata do cabeçalho mais alguns píxeis de margem. Abra as DevTools (F12), selecione o elemento
headerdo seu site e verifique a suaheightno separador Computed. Por exemplo, se o cabeçalho tiver 80px, use 90 no seu código. Se a versão móvel tiver uma altura de cabeçalho diferente, adicione uma media query com um cálculo de deslocamento dinâmico.
O jQuery ainda é relevante em 2026?
Sim, especialmente no ecossistema WordPress. O jQuery permanece no núcleo do WP, muitos plugins e temas dependem dele, e migrar todo o ecossistema para JS nativo levará anos. Para novos projetos em JavaScript puro, o scroll suave faz-se via
element.scrollIntoView({ behavior: 'smooth' })ouscroll-behavior: smoothem CSS, com significativamente menos linhas de código. Mas se estiver a modificar um site WP existente, a solução jQuery continua a ser fiável e adequada.
Posso evitar completamente o jQuery?
Pode e deve, se o projeto for novo. O equivalente nativo do script básico:
1 document.addEventListener('DOMContentLoaded', () => { 2 const hash = window.location.hash; 3 if (hash) { 4 window.location.hash = ''; 5 const target = document.querySelector(hash); 6 if (target) { 7 window.scrollTo({ 8 top: target.getBoundingClientRect().top + window.pageYOffset - 110, 9 behavior: 'smooth' 10 }); 11 } 12 window.location.hash = hash; 13 } 14 });
Mesmo princípio: guarde o hash, limpe-o, faça scroll, restaure-o. A diferença é que
behavior: 'smooth'usa o motor CSS nativo do navegador em vez de um temporizador jQuery. Não pode configurar a velocidade, mas o código é 30 KB mais leve (o peso do jQuery).
Porquê $('html, body') em vez de apenas $('html')?
O Firefox faz scroll no
html, o Chrome usa obodye o Safari depende da versão. Especificar ambos os seletores noanimate()garante que funciona em todos os navegadores: o jQuery envia a animação para o elemento que realmente a aplicar.
Vale a pena usar jQuery apenas para scroll suave em 2026
Se tem um site WordPress ou um projeto legado onde o jQuery já está carregado, aproveite o script deste artigo e não complique. Dez linhas de código que funcionam em todo o lado, em qualquer navegador, sem necessidade de polyfills. Para novos projetos em JavaScript puro, use o nativo scroll-behavior: smooth ou scrollIntoView(). Ambas as abordagens produzem scroll suave, mas o método jQuery dá-lhe controlo sobre a velocidade, o deslocamento e o seletor do contentor de scroll. As implementações nativas exigem verificações separadas para alcançar o mesmo.
A regra principal que aprendemos em dezenas de projetos: limpe sempre o hash antes de fazer scroll. Sem este truque, nenhum handler consegue vencer o comportamento nativo do navegador e os utilizadores continuarão a sofrer saltos abruptos.



