jQuery / Criar um link suave para voltar ao topo
Crie um link real href="#top" e acrescente jQuery .animate({ scrollTop: 0 }) ao elemento que rola o documento. Evite o salto imediato mantendo a âncora para funcionar sem JavaScript. Respeite movimento reduzido e leve o foco ao título superior ao terminar.
Escolher destino e link básico
O exemplo move a página inteira. document.scrollingElement retorna seu elemento de rolagem real, a raiz no modo padrão. Mantenha <!doctype html>. Um alvo evita efeitos e callbacks separados em html e body.
Dê id="top" ao título e aponte o link para ele. tabindex="-1" permite foco por código sem acrescentar uma parada à navegação Tab normal. Só rolar pode deixar o foco embaixo, portanto trate-o separadamente.
Exemplo completo em um arquivo
Salve tudo em UTF-8 como back-top-demo.html e abra no navegador. A Internet carrega o arquivo oficial completo do jQuery 4.0.0. A animação precisa de effects, não slim. Não exige servidor nem instalação.
Go to 900px cria a posição de comparação; o link inferior direito continua acessível. A página tem altura para rolar. A barra fixa é didática: evite sobrepor cabeçalhos e anúncios em um site real.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Smooth back-to-top link</title>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<style>
html { scroll-behavior: auto; }
body { font: 16px/1.6 sans-serif; margin: 0; padding: 100px 20px; min-height: 2400px; box-sizing: border-box; }
#top { max-width: 760px; margin: 0; }
#top:focus { outline: 3px solid teal; }
#toolbar { position: fixed; top: 0; left: 0; right: 0; background: #fff; padding: 12px; z-index: 2; }
button, a { font: inherit; }
button { margin: 4px; }
#back { position: fixed; right: 16px; bottom: 16px; padding: 10px 14px; background: #075d55; color: #fff; border-radius: 6px; z-index: 2; }
#status { position: fixed; left: 12px; bottom: 70px; max-width: calc(100% - 48px); padding: 8px; background: #fff; white-space: pre-wrap; overflow-wrap: anywhere; }
.spacer { margin-top: 700px; }
</style>
</head>
<body>
<div id="toolbar"><button type="button" id="down">Go to 900px</button><button type="button" id="stop">Stop movement</button></div>
<h1 id="top" tabindex="-1">Top of the example page</h1>
<p>Use the fixed link after scrolling down.</p>
<p class="spacer">Middle of the page</p>
<p class="spacer">Lower content</p>
<a id="back" href="#top">Back to top</a>
<pre id="status" aria-live="polite"></pre>
<script>
$(function () {
const root = document.scrollingElement;
if (!root) return;
const $root = $(root);
let completed = 0, state = "ready";
function report() { $("#status").text(`scrollY=${Math.round(window.scrollY)}\ncompleted=${completed}\nstate=${state}`); }
function interrupt() {
if (state !== "moving") return;
$root.stop(true, false); state = "interrupted"; report();
}
$("#back").on("click.backTopLesson", function (event) {
event.preventDefault();
$root.stop(true, false);
state = "moving"; report();
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
$root.animate({ scrollTop: 0 }, { duration: reduce ? 0 : 600, complete: function () {
completed++; state = "done";
document.getElementById("top").focus({ preventScroll: true });
report();
} });
});
$("#down").on("click", function () { $root.stop(true, false).scrollTop(900); completed = 0; state = "ready"; report(); });
$("#stop").on("click", interrupt);
$(window).on("scroll.backTopLesson", report);
$(window).on("wheel.backTopLesson touchstart.backTopLesson", interrupt);
$(document).on("keydown.backTopLesson", function (event) {
if (["ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", " "].includes(event.key)) interrupt();
});
report();
});
</script>
</body>
</html>
Saída inicial no topo. Arredondar só facilita a leitura, sem limitar cálculos a inteiros.
scrollY=0
completed=0
state=ready
- Pressione Go to 900px. Se a área visível for alta demais para chegar a 900, reduza a altura.
- Back to top retorna normalmente em 600ms. scrollY cai até zero e mostra completed=1, state=done.
- Aparece o contorno do título focado. Confira o link com teclado e Enter.
- De 900, repetir cliques não acumula viagens: para a anterior e reinicia da posição atual.
- Stop movement interrompe no meio com state=interrupted. Reative o link ou restaure 900 para comparar.
Ações, teclado, repetições, parada e movimento reduzido foram executados com 3.7.1 e 4.0.0 no Edge para Windows. Outra verificação sem JavaScript seguiu a âncora #top.
Cliques, interrupção e movimento reduzido
O alvo de .animate() é scrollTop numérico zero. Sem event.preventDefault(), o salto nativo compete com a animação. .stop(true, false) limpa a fila e para sem concluir no destino. Novos cliques partem do ponto atual sem executar callbacks anteriores.
Roda, início de toque e teclas de rolagem chamam interrupt() para devolver controle. Não bloqueiam a rolagem com preventDefault. Stop usa a mesma função. Interromper não força foco no topo.
prefers-reduced-motion é conferido a cada ativação. Com essa preferência, a duração é zero e a mesma conclusão move o foco. Os efeitos globais do jQuery não mudam.
focus({ preventScroll: true }) evita uma segunda mudança de posição. Outros destinos exigem calcular coordenadas e possível cabeçalho fixo; só trocar o id não basta.
Adaptar a um site existente
Confira id="top" existente e correspondência do link. Restrinja seletores e namespaces para preservar outros manipuladores. Controle 900px, status e altura artificial são recursos de prática.
Não combine CSS scroll-behavior:smooth e animação jQuery no mesmo percurso. Aqui auto deixa o tempo com jQuery. Sem jQuery, window.scrollTo() com smooth é uma opção; adapte conclusão e foco.
Sem movimento, confira espaço de rolagem, contêiner interno e carregamento completo. Revise texto, contraste, área de toque e sobreposição de elementos fixos. Mantenha href útil em vez de javascript: ou endereço vazio.




