Scroll suavizado nativo com CSS e JS puro

Scroll suavizado nativo com CSS e JS puro

Você quer scroll suavizado? Esqueça o JQuery, já passamos disso. Permita-me lhe apresentar nossas ferramentas nativas para scroll suavizado.

LinkCSS scroll-behavior

A propriedade scroll-behavior em CSS aceita um de três valores ou dois, na verdade, já que um deles foi descontinuado.

  1. scroll-behavior: auto é o comportamento padrão de scroll instantâneo que já estamos acostumados.
  2. scroll-behavior: instant é o mesmo que auto, por isso foi descontinuado. Se quiser esse comportamento, use auto.
  3. scroll-behavior: smooth aplica uma transição suave quando um evento de scroll é acionado programaticamente.

Eu digo "acionado programaticamente" porque ele não vai suavizar o scroll do mouse.

Algumas formas de acionar um evento de scroll programaticamente são:

JavaScript
-	Window.scrollTo()
-	Window.scrollBy()
-	Element.scrollTo()
-	Element.scrollBy()
-	Element.scrollIntoView()
-	Element.scrollLeft = x
-	Element.scrollTop = y

Exploraremos esses métodos individualmente.

Link(Nota) Window.scroll() e Element.scroll()

Talvez você tenha percebido que eu não mencionei o método scroll().

Isso é porque Window.scroll() e Element.scroll() são efetivamente o mesmo que Window.scrollTo() e Element.scrollTo(). Para evitar conteúdo duplicado, vou me referir apenas a scrollTo(). Na prática, você pode usar qualquer um, escolha um e seja consistente.

LinkWindow.scrollTo() e Element.scrollTo()

São ideais para rolar usando coordenadas absolutas. Se você tiver as coordenadas x e y para onde deseja rolar o usuário, você pode simplesmente chamar window.scrollTo(x, y) e ele vai respeitar a propriedade CSS scroll-behavior da pagina.

O mesmo se aplica para elementos roláveis. Você simplesmente chama element.scrollTo(x, y) e ele vai respeitar a propriedade CSS scroll-behavior do elemento.

Também existe uma nova assinatura para este método, que usa um objeto ao invés de dois argumentos numéricos, e com esta nova assinatura, podemos definir o comportamento de scroll explicitamente.

JavaScript
// For window
window.scrollTo({
    left: x,
    top: y,
    behavior: 'smooth'
});

// For element
const el = document.querySelector(...);
el.scrollTo({
    left: x,
    top: y,
    behavior: 'smooth'
});

LinkElement.scrollLeft e Element.scrollTop

Definir as propriedades .scrollLeft e .scrollTop de um elemento é o mesmo que chamar Element.scrollTo(). Ele vai respeitar a propriedade CSS scroll-behavior do elemento.

JavaScript
const el = document.querySelector(...);
const x = 100;
const y = 500;

// Setting .scrollLeft and .scrollTop with smooth scroll
el.style.scrollBehavior = 'smooth';
el.scrollLeft = x;
el.scrollTop = y;

// Is the same as calling Element.scrollTo()
el.scrollTo({ left: x, top: y, behavior: 'smooth' });

Link(Nota) Element.scrollLeft negativo

Se a direction do seu elemento é rtl, scrollLeft = 0 marca a posição mais à direita da rolagem horizontal e o valor diminui conforme você vai para a esquerda.

Para um elemento rolável com 100px de largura, 500px de largura de rolagem e direção rtl, a posição mais à esquerda scrollLeft = -400.

HTML
<div id="scrollable" style="width: 100px; overflow: auto" dir="rtl">
  <div style="width: 500px; height: 100px; background: green"></div>
</div>
<p id="output"></p>

JavaScript
const scrollable = document.querySelector('#scrollable');
const output = document.querySelector('#output');

const updateOutput = () => {
  output.textContent = `scrollLeft: ${scrollable.scrollLeft}`;
};

updateOutput();
scrollable.addEventListener('scroll', updateOutput);

LinkWindow.scrollBy() e Element.scrollBy()

Este elemento tem exatamente as mesmas assinaturas que Window.scrollTo() e Element.scrollTo(). Ele aceita x e y como dois argumentos numéricos ou um único argumento sendo um objeto com as propriedades opcionaisleft, top e behavior.

A diferença aqui é que não estamos passando coordenadas absolutas, mas sim valores relativos. Se chamamos scrollBy({ top: 10 }), estamos rolando 10 pixels para baixo de onde estamos atualmente, não 10 pixels para baixo do início da página.

JavaScript
// For window
window.scrollBy({ top: 10 }); // Scroll 10px down
window.scrollBy({ left: 20 }); // Then 20px to the right
window.scrollBy({ top: 50 }); // And then 50px down

// For element
const el = document.querySelector(...);
el.scrollBy({ top: 10 }); // Scroll 10px down
el.scrollBy({ left: 20 }); // Then 20px to the right
el.scrollBy({ top: 50 }); // And then 50px down

Link(Nota) Window.scrollByLines() e Window.scrollByPages()

Firefox vai um pouco mais longe implementando métodos para rolar por uma quantidade de linhas ou páginas. É um recurso fora do padrão que só funciona no Firefox, então você provavelmente não vai querer usar isso em produção.

Você pode obter um efeito semelhante em todos os navegadores principais convertendo100vh (para uma página) e 1rem (para uma linha) para pixels e passando esse valor para Window.scrollBy().

JavaScript
const toPixels = require('to-px'); // From NPM

const page = toPixels('100vh');
window.scrollBy(0, page); // window.scrolByPages(1)
const line = toPixels('1rem');
window.scrollBy(0, line); // window.scrolByLines(1)

LinkElement.scrollIntoView()

Mas na maioria das vezes, não nos importamos com coordenadas fixas, só queremos rolar o usuário até um elemento específico na página. Isso pode ser feito mais facilmente (e mais explicitamente) com Element.scrollIntoView().

Este método pode ser chamado sem argumentos, isso rolará a página (respeitando o CSS scroll-behavior) até que o elemento esteja alinhado no topo. (A menos que o elemento esteja no fundo da página, nesse caso, ele rolará o máximo possível).

HTML
<div style="height: 2000px">Some space</div>
<div id="target" style="background: green">Our element</div>
<div style="height: 500px">More space</div>

JavaScript
const target = document.querySelector('#target');
target.scrollIntoView();

Você pode personalizar ainda mais o posicionamento do elemento na visualização passando um booleano ou um objeto.

JavaScript
const el = document.querySelector(...);

// Default, aligns at the top
el.scrollIntoView(true);

// Aligns at the bottom
el.scrollIntoView(false);

// Aligns vertically at the center
el.scrollIntoView({ block: 'center' });

// Vertical top and horizontal center
el.scrollIntoView({ block: 'start', inline: 'center' });

// Vertical bottom and horizontal right
el.scrollIntoView({ block: 'end', inline: 'end' });

// Vertical center and smooth
el.scrollIntoView({ block: 'center', behavior: 'smooth' });

// Vertical nearest
el.scrollIntoView({ block: 'nearest' });

Ao usar um objeto para definir o posicionamento do elemento, observe que block se refere ao posicionamento vertical e inline se refere ao posicionamento horizontal. Além disso, o posicionamento 'nearest' pode ser o topo/esquerda ou a parte inferior/direita, o que estiver mais próximo. E também pode ser nada, se o elemento já estiver visível.

LinkSuporte dos navegadores

No momento da escrita deste artigo, todos os principais navegadores – exceto o Safari – suportam scroll suavizado e os métodos apresentados neste artigo

Se você precisar de mais garantias, existe um polyfill para scroll suavizado muito bom que eu uso em meus projetos. Ele suporta scroll(), scrollTo(), scrollBy(), scrollIntoView() e a propriedade scroll-behavior em CSS. Ele não suporta rolagem suavizada definindo as propriedades scrollLeft/scrollTop e também não suporta as opções para a função scrollIntoView() (sempre alinha o elemento no topo).

Se você tiver mais curiosidade, eu sugiro estudar o código-fonte do polyfill. São menos de 500 linhas no total. Fiz uma PR para melhorar um pouco a documentação, talvez você tenha mais facilidade de entender o código com isso.

LinkCTA

Referências para tudo o que eu disse estão nas referências abaixo.

Tenha um ótimo dia e nos vemos em breve.

LinkReferencias

  1. CSS scroll-behavior: smooth MDN
  2. Element.scrollTop MDN
  3. Element.scrollLeft MDN
  4. Smooth scroll polyfill Repositório do iamdustan no GitHub
  5. Smooth scroll polyfill métodos suportados I am Dustan
  6. scroll-behavior: instant renomeado para auto - CSS Working Group
  7. Opções block e inline para scrollIntoView() - Stack Overflow
  8. Suporte do navegador para Smooth scroll Can I Use
  9. Especificação do CSS para scroll-behavior Drafts
  10. Proposta do Smooth scroll para scrollTo()

Assine a nossa Newsletter e seja avisado quando eu lançar um curso, postar um vídeo ou escrever um artigo.

Campo obrigatório
Campo obrigatório