Rolagem suave para div específico no clique

91

O que estou tentando fazer é fazer com que, se você clicar em um botão, ele role para baixo (suavemente) até um div específico na página.

O que eu preciso é que se você clicar no botão, ele rola suavemente até o div 'segundo'.

.first {
    width: 100%;
    height: 1000px;
    background: #ccc;
}

.second {
    width: 100%;
    height: 1000px;
    background: #999;
}
<div class="first"><button type="button">Click Me!</button></div>
<div class="second">Hi</div>

Erik Fischer
fonte
Você pode tentar este plugin , embora este seja muito mais amigável. Você só precisa vincular o arquivo JS no cabeçalho e alterar sua marcação de forma adequada para que funcione.
joshrathke
1
isso deve ajudá-lo :: stackoverflow.com/questions/3432656/…
Sudhir Bastakoti

Respostas:

177

Faz:

$("button").click(function() {
    $('html,body').animate({
        scrollTop: $(".second").offset().top},
        'slow');
});

Jsfiddle atualizado

Sudhir Bastakoti
fonte
Você está usando javaScript aqui ou jQuery?
1
@FahadUddin é jQuery.
Sudhir Bastakoti
@SudhirBastakoti: Por que o JsFiddle não incluiu a biblioteca jquery para ele nessa página?
@Sudhir Bastakoti, mas muitos usuários reclamam que a rolagem não é suave.
Maulik
39

Existem muitos exemplos de rolagem suave usando bibliotecas JS como jQuery, Mootools, Prototype, etc.

O exemplo a seguir está em JavaScript puro. Se você não tem jQuery / Mootools / Prototype na página ou não quer sobrecarregar a página com pesadas bibliotecas JS, o exemplo será útil.

http://jsfiddle.net/rjSfP/

Parte HTML:

<div class="first"><button type="button" onclick="smoothScroll(document.getElementById('second'))">Click Me!</button></div>
<div class="second" id="second">Hi</div>

Parte CSS:

.first {
    width: 100%;
    height: 1000px;
    background: #ccc;
}

.second {
    width: 100%;
    height: 1000px;
    background: #999;
}

Parte JS:

window.smoothScroll = function(target) {
    var scrollContainer = target;
    do { //find scroll container
        scrollContainer = scrollContainer.parentNode;
        if (!scrollContainer) return;
        scrollContainer.scrollTop += 1;
    } while (scrollContainer.scrollTop == 0);

    var targetY = 0;
    do { //find the top of target relatively to the container
        if (target == scrollContainer) break;
        targetY += target.offsetTop;
    } while (target = target.offsetParent);

    scroll = function(c, a, b, i) {
        i++; if (i > 30) return;
        c.scrollTop = a + (b - a) / 30 * i;
        setTimeout(function(){ scroll(c, a, b, i); }, 20);
    }
    // start scrolling
    scroll(scrollContainer, scrollContainer.scrollTop, targetY, 0);
}
nico
fonte
Estou usando isso e funciona muito bem. Como faço a rolagem mais lenta?
Jamescampbell
Alguma ideia de como adicionar deslocamento para navbar fixo neste código? Aqui está um exemplo que fiz violino
Plavookac
3
Ainda útil após 5 anos
Owaiz Yusufi
9

Eu brinquei com a resposta de nico um pouco e me senti nervosa. Fiz uma investigação e descobri window.requestAnimationFramequal é a função que é chamada a cada ciclo de repintura. Isso permite uma animação de aparência mais limpa. Ainda estou tentando aprimorar os bons valores padrão para o tamanho do passo, mas para o meu exemplo, as coisas parecem muito boas usando esta implementação.

var smoothScroll = function(elementId) {
    var MIN_PIXELS_PER_STEP = 16;
    var MAX_SCROLL_STEPS = 30;
    var target = document.getElementById(elementId);
    var scrollContainer = target;
    do {
        scrollContainer = scrollContainer.parentNode;
        if (!scrollContainer) return;
        scrollContainer.scrollTop += 1;
    } while (scrollContainer.scrollTop == 0);

    var targetY = 0;
    do {
        if (target == scrollContainer) break;
        targetY += target.offsetTop;
    } while (target = target.offsetParent);

    var pixelsPerStep = Math.max(MIN_PIXELS_PER_STEP,
                                 (targetY - scrollContainer.scrollTop) / MAX_SCROLL_STEPS);

    var stepFunc = function() {
        scrollContainer.scrollTop =
            Math.min(targetY, pixelsPerStep + scrollContainer.scrollTop);

        if (scrollContainer.scrollTop >= targetY) {
            return;
        }

        window.requestAnimationFrame(stepFunc);
    };

    window.requestAnimationFrame(stepFunc);
}
Ned Rockson
fonte
1
@Alfonso Veja acima. Esta é simplesmente uma versão otimizada do código de Nico em uma resposta anterior.
Ned Rockson
@NedRockson não funciona para mim dá a mensagem de console "Uncaught TypeError: Não é possível ler a propriedade 'parentNode' de null" mas o código de Nico está funcionando. O que devo fazer para aplicar animação limpa?
Kartik Watwani
@KartikWatwani Isso significa que na leitura da linha scrollContainer = scrollContainer.parentNode, scrollContainer é nulo. Isso provavelmente significa que você não está transmitindo o correto elementIdao chamar esta função. Também é possível que você esteja executando este script em uma página onde o elementId não existe.
Ned Rockson
@NedRockson Se elementIdestivesse errado, eu teria recebido o mesmo erro no caso do exemplo de @nico, mas nesse caso a rolagem está funcionando, mas não sem problemas.
Kartik Watwani
Usar em requestAnimationFramevez de setTimeouté o caminho a seguir. setTimeoutnão deve ser usado para animações.
tsnkff
2

Peguei a versão de Ned Rockson e ajustei para permitir rolar para cima também.

var smoothScroll = function(elementId) {
  var MIN_PIXELS_PER_STEP = 16;
  var MAX_SCROLL_STEPS = 30;
  var target = document.getElementById(elementId);
  var scrollContainer = target;
  do {
    scrollContainer = scrollContainer.parentNode;
    if (!scrollContainer) return;
    scrollContainer.scrollTop += 1;
  } while (scrollContainer.scrollTop === 0);

  var targetY = 0;
  do {
    if (target === scrollContainer) break;
    targetY += target.offsetTop;
  } while (target = target.offsetParent);

  var pixelsPerStep = Math.max(MIN_PIXELS_PER_STEP,
    Math.abs(targetY - scrollContainer.scrollTop) / MAX_SCROLL_STEPS);

  var isUp = targetY < scrollContainer.scrollTop;

  var stepFunc = function() {
    if (isUp) {
      scrollContainer.scrollTop = Math.max(targetY, scrollContainer.scrollTop - pixelsPerStep);
      if (scrollContainer.scrollTop <= targetY) {
        return;
      }
    } else {
        scrollContainer.scrollTop = Math.min(targetY, scrollContainer.scrollTop + pixelsPerStep);

      if (scrollContainer.scrollTop >= targetY) {
        return;
      }
    }

    window.requestAnimationFrame(stepFunc);
  };

  window.requestAnimationFrame(stepFunc);
};
Marek Lisý
fonte
2

Você pode usar css básico para obter uma rolagem suave

html {
  scroll-behavior: smooth;
}
Sardorbek Khalimov
fonte