Smooth Scrolling - JavaScript & CSS
Published: 2024-02-18 14:44:36

Kali ini kita akan mendemokan _smooth scrolling_, yaitu efek beerganti posisi secara _smooth_/halus. _Smooth scrolling_ sendiri bisa dibilang merupakan fitur wajib dalam sebuah halaman web, tentunya supaya efek _smooth scroling_ terlihat, setting animation effect (pada Window 11) harus aktif, untuk versi window lain silahkan diaktifkan. Untuk Mac saya tidak tahu settingnya dimana sebab belum pernah pegang Macbook, yang jelas meskipun efek _smooth scrolling_ pada browser sudah aktif namun jika animation effect pada sistem operasi tidak aktif maka percuma saja. Pada demo kali kita akan mencoba 3 jenis metode scrolling yaitu :

- Scrolling biasa
- Smooth scrolling cara lama
- Smooth scrolling cara baru

Pertama-tama buatlah file html, css dan js. Untuk template kode file html dan css sebagai berikut.

_index.html_
```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="styles.css" />
    <title>Document</title>
  </head>
  <body>
    <header>
      <ul>
        <li><button class="btnScroll1">Section 1</button></li>
        <li><button class="btnScroll2">Section 2</button></li>
        <li><button class="btnScroll3">Section 3</button></li>
      </ul>
    </header>
    <section class="section" id="section-1">
      <p>This is section 1</p>
    </section>
    <section class="section" id="section-2">
      <p>This is section 2</p>
    </section>
    <section class="section" id="section-3">
      <p>This is section 3</p>
    </section>
    <script src="smooth.js"></script>
  </body>
</html>
```

_styles.css_
```css
:root {
  --color-primary: #fd424b;
}

* {
  margin: 0;
  padding: 0;
  border: 0;
}

header {
  color: var(--color-primary);
  font-size: 30px;
  font-weight: bold;
  background-color: rgb(239, 245, 58);
  margin-top: 0px;
  top: 0;
  width: 100%;
  position: sticky;
  /* position: fixed; */
}

ul {
  list-style: none;
  display: flex;
}

li {
  margin: 0 20px;
}

button {
  background-color: rgb(239, 245, 58);
  font-size: 20px;
  font-weight: bold;
}

button:hover {
  color: #fd424b;
  cursor: pointer;
}

.section {
  height: 1000px;
}

#section-1 {
  background-color: rgb(243, 125, 52);
}

#section-2 {
  background-color: rgb(173, 243, 52);
}

#section-3 {
  background-color: rgb(66, 150, 246);
}

p {
  font-weight: bold;
  font-size: 100px;
  padding-top: 34.667px;
}
```
**Scrolling biasa**
Scrolling dengan metode ini agak rumit, meskipun sudah jarang sekali dipakai (karena ada metode baru yang lebih sederhana) tapi saya pikir perlu sebagai dasar pemahaman. Metode scrolling ini membutuhkan koordinat (X dan Y, atau left dan top) posisi tujuan. Darimana kita bisa mendapatkan koordinat tersebut ? Dengan metode `getBoundingClientRect();` kita bisa mengambil koordinat posisi yang kita inginkan. Berikut kode JavaScript-nya.

```javascript
'use strict';

// Smooth scrolling
const btnScroll1 = document.querySelector('.btnScroll1');
const btnScroll2 = document.querySelector('.btnScroll2');
const btnScroll3 = document.querySelector('.btnScroll3');
const section1 = document.querySelector('#section-1');
const section2 = document.querySelector('#section-2');
const section3 = document.querySelector('#section-3');

btnScroll1.addEventListener('click', function (e) {
  const sect1coord = section1.getBoundingClientRect();
  console.log(sect1coord);
  console.log('left/top:', sect1coord.left, sect1coord.top);
});
```
Halaman web belum saya manipulasi, artinya posisi `<section class="section" id="section-1>` adalah pada posisi default, jika kita klik menu Section 1 hasilnya sebagai berikut.

![result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w6r9ug91d6sqkxquwi7t.png)
Koordinat x/left bernilai 0 sedangkan koordinat y/top bernilai 34.6666 (dalam satuan pixel). Kenapa kita harus mengetahui kordinat tersebut ? Sebab koordinat itulah nanti yang akan menjadi posisi tujuan scrolling kita, kalau kita set koorniat x/y = 0/0 kan sama saja ? Benar jika posisi yang kita tuju berada pada posisi teratas, namun dengan semakin kompleksnya halaman web posisi scrolling tidak mesti menuju halaman paling atas. Sekarang mari kita implementasikan scrolling pada event handler diatas.

```javascript
btnScroll1.addEventListener('click', function (e) {
  const sect1coord = section1.getBoundingClientRect();
  console.log(sect1coord);
  console.log('left/top:', sect1coord.left, sect1coord.top);

  // Scrolling
  window.scrollTo(sect1coord.left, sect1coord.top);
});
```

![result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/feyp2oif3qbkejjmaz5x.gif)

Apa yang terjadi ? Scrooling kita berfungsi tapi kenapa lompat-lompat ? Itu dikarenakan metode `getBoundingClientRect();` bersifat relatif terhadap viewport, artinya koordinat x/y atau letf/top posisinya akan berubah sesuai dengan halaman web yang terlihat. Untuk mengatasinya bisa kita lakukan beberapa hal, yang pertama adalah mengubah posisi `header` pada file css dari `sticky` menjadi `fixed`, silahkan dicoba. Yang kedua adalah menyertakan posisi window scroll pada tujuan sebagai berikut.

```javascript
btnScroll1.addEventListener('click', function (e) {
  const sect1coord = section1.getBoundingClientRect();
  console.log(sect1coord);
  console.log('left/top:', sect1coord.left, sect1coord.top);

  // Scrolling
  window.scrollTo(sect1coord.left + window.scrollX, sect1coord.top + window.scrollY);
});
```
Untuk smooth scrolling cara lama dan cara baru kita implementasikan ke Section 2 dan Section 3, kode programnya sebagai berikut.

```javascript
btnScroll2.addEventListener('click', function (e) {
  const sect2coord = section2.getBoundingClientRect();

  // Smooth scrolling cara lama
  window.scrollTo({
    left: sect2coord.left + window.scrollX,
    top: sect2coord.top + window.scrollY,
    behavior: 'smooth',
  });
});

btnScroll3.addEventListener('click', function (e) {
  // Smooth scrolling cara baru
  section3.scrollIntoView({ behavior: 'smooth' });
});
```
Hasilnya adalah sebagai berikut.

![result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/af1w27jacr2pfj90fl1x.gif)