jQuery / Plugin / jQuery Smooth Scroll

jQuery Smooth Scroll anima a navegação dentro da mesma página, como href="#beta". Selecione links e chame .smoothScroll(); speed controla a duração e offset ajusta o destino. Inclua foco no destino e movimento reduzido para permitir continuar a navegação após o efeito visual.

Escopo e dependências

É usado jquery-smooth-scroll de kswedberg, diferente de bibliotecas de roda com nome semelhante. href="#beta" deve corresponder a um id="beta" único no mesmo documento.

O exemplo fixa o plugin CDN 2.2.0 e jQuery completo 4.0.0. Carregue jQuery, plugin e inicialização nessa ordem. Slim não possui os efeitos necessários. O mesmo plugin foi executado com 4.0.0 e 3.7.1 no Windows Edge; isso não valida toda combinação de tema e outros plugins.

Somente os dois links .js-scroll do menu são aprimorados. Native jump e o link no conteúdo continuam nativos, permitindo comparar. Restrinja o seletor aos links com essa finalidade em vez de alterar todos os a do site.

Exemplo completo com foco e margem

Salve e abra smooth-scroll-demo.html em UTF-8. Não exige servidor ou compilação; a internet carrega dois scripts. Seções altas e espaço final tornam o alinhamento observável.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Same-page smooth scrolling</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-smooth-scroll/2.2.0/jquery.smooth-scroll.min.js"></script>
  <style>
    :root { --anchor-gap: 100px; }
    html { scroll-behavior: auto; }
    body { font: 16px/1.6 sans-serif; margin: 20px; padding-top: var(--anchor-gap); }
    #menu { position: fixed; top: 0; left: 0; right: 0; padding: 12px; background: #e6f4f1; z-index: 10; }
    #menu a, #menu button { display: inline-block; margin: 4px 8px; font: inherit; }
    section { min-height: 700px; max-width: 700px; }
    h2 { scroll-margin-top: var(--anchor-gap); }
    h2:focus { outline: 3px solid teal; }
    footer { min-height: 100vh; }
  </style>
</head>
<body>
  <nav id="menu" aria-label="Sections">
    <a class="js-scroll" href="#alpha">Alpha</a>
    <a class="js-scroll" href="#beta">Beta</a>
    <a href="#native">Native jump</a>
    <button type="button" id="reset">Reset</button>
    <span id="status" role="status">Native links available.</span>
  </nav>
  <h1>Explore the sections</h1>
  <section><h2 id="alpha" tabindex="-1">Alpha</h2><p>First destination. Text remains available without JavaScript.</p></section>
  <section><h2 id="beta" tabindex="-1">Beta</h2><p>Second destination. Tab can continue to <a href="#native">the next destination</a>.</p></section>
  <section><h2 id="native" tabindex="-1">Native destination</h2><p>This menu link is not enhanced by the plugin.</p></section>
  <footer>Enough space to align the last heading below the menu.</footer>
  <script>
    jQuery(function ($) {
      if (typeof $.fn.smoothScroll !== "function") return;
      const $menu = $("#menu"), $status = $("#status"), duration = 600;
      function gap() {
        const value = $menu.outerHeight() + 12;
        document.documentElement.style.setProperty("--anchor-gap", value + "px");
        return value;
      }
      gap(); $(window).on("resize.demo", gap);
      $("#menu a.js-scroll").smoothScroll({
        speed: duration, easing: "swing", autoFocus: true,
        beforeScroll: function (options) {
          options.offset = -gap();
          options.speed = window.matchMedia("(prefers-reduced-motion: reduce)").matches ? 0 : duration;
          $status.text("Moving to " + options.scrollTarget);
        },
        afterScroll: function (options) {
          history.replaceState(null, "", options.scrollTarget);
          $status.text("Arrived at " + options.scrollTarget);
        }
      });
      $("#reset").on("click", function () {
        $("html, body").stop(true, false); window.scrollTo(0, 0);
        history.replaceState(null, "", location.pathname + location.search);
        $status.text("Ready; enhanced links: 2.");
      });
      $status.text("Ready; enhanced links: 2.");
    });
  </script>
</body>
</html>

Depois de inicializar, o menu mostra este estado. Sem JavaScript, Native links available. permanece e os links de fragmento continuam funcionando.

Ready; enhanced links: 2.
  1. Selecione Beta. Em cerca de 600ms aparece Arrived at #beta e o título fica 12px abaixo do menu.
  2. Reset volta ao topo e remove o fragmento. Focalize Alpha ou Beta pelo teclado e pressione Enter.
  3. O destino recebe contorno de foco. Depois de Beta, Tab continua até o link abaixo.
  4. Native jump não passa pelo plugin nem altera seu aviso de chegada.
  5. Ative movimento reduzido reduce: duração zero, mantendo destino e conclusão.
  6. Altere a largura até o menu quebrar linhas e confira que o título continua visível. Reinicie para comparar.

tabindex="-1" permite foco programático no título sem criar uma parada Tab comum. autoFocus=true move o foco na chegada, em vez de deixar a navegação por teclado no menu.

Tempo, coordenadas e histórico

speed representa aqui duração em milissegundos. Valor menor percorre mais rápido a mesma distância. Mude a constante duration de 600 para 1200 no mesmo destino e restaure 600. Para easing, mantenha o tempo e troque swing por linear. Outros nomes precisam de extensão apropriada.

offset é somado à coordenada do destino. Espaço acima exige valor negativo: altura real do menu mais 12px com sinal menos. beforeScroll mede novamente e acompanha a quebra de linhas. Valor positivo avança além e pode esconder o título sob o menu fixo.

scroll-margin-top atende aos links nativos; o plugin usa offset numérico. Não suponha que CSS substitua esse cálculo. Confira os dois caminhos.

O plugin normalmente impede a ação padrão. Na chegada, history.replaceState() modifica o fragmento substituindo a entrada atual. Cada destino não acrescenta uma etapa ao botão Voltar. Navegação hashchange não foi implementada. Aplicações que exigem Voltar/Avançar precisam de política própria de histórico.

Reset interrompe efeitos e fila, restaura posição, fragmento e estado. Mudanças rápidas de destino também foram verificadas. Isso não implementa cancelamento por todo sinal de roda ou entrada do usuário.

Alternativa CSS e diagnóstico

Para âncoras simples, scroll-behavior pode bastar. O CSS abaixo substitui o plugin, sem ser usado junto. Remova os dois scripts externos, a inicialização, Reset e a indicação de estado. Troque a regra html auto existente. Mantenha scroll-margin-top e ajuste a margem à altura real do menu.

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

Esse caminho usa fragmentos e histórico nativos, sem duração em milissegundos ou callbacks do plugin. A consulta de mídia reduz o movimento. Já o exemplo jQuery mantém auto no CSS para evitar dois sistemas concorrentes.

Para smoothScroll is not a function, examine respostas Network e ordem de carregamento. Uma segunda cópia de jQuery depois do plugin pode perder sua extensão. No WordPress, confira primeiro as dependências registradas pelo tema.

Sem movimento, verifique IDs ausentes ou repetidos, href real e seleção. Para desalinhamento, confira altura do menu, imagens ou fontes que mudam o layout e espaço no fim do documento. Um contêiner interno exige configuração scrollElement e testes no seu sistema de coordenadas.