Blurr Element - JavaScript & CSS
Published: 2024-06-12 15:54:25

Two articles in a row, sebenarnya sudah lama hanya tinggal menulis ulang saja. Kali ini kita akan membuat blurr effect, semacam efek kabur yang dapat diaplikasikan pada menu untuk menampilkan fokus. Jadi idenya ketika mouse berada pada menu tertentu, menu yang lain akan nge-blur. Kita akan menerapkan blurr effect dengan 3 metode berbeda. Siapkan 3 file andalan kita.

```html
<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Blurr Effect</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="header">
      <div class="menu">
        <a class="link" href="#">Hello</a>
        <a class="link" href="#">How</a>
        <a class="link" href="#">Are</a>
        <a class="link" href="#">You</a>
      </div>
    </div>
    <script src="app.js"></script>
  </body>
</html>
```

```css
/* style.css */

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

.header {
  height: 100vh;
  background-color: burlywood;
  display: flex;
  align-items: center;
  justify-content: center;
}

.header .menu {
  background-color: chocolate;
  width: 900px;
  display: flex;
  justify-content: space-around;
  height: 100px;
  align-items: center;
  font-size: 50px;
  font-weight: bolder;
  border-radius: 9999px;
  border: 2px solid #efefef;
}

.header .menu a {
  text-decoration: none;
  transition: all 0.7s ease-out;
}
```
**Cara Pertama**

Kita akan menggunakan event _mouseover_ dan _mouseout_ serta memanfaatkan DOM traversal _closest_. Untuk _closest_ sudah pernah kita gunakan pada proyek sebelumnya, saya sendiri juga termasuk yang baru mengetahui metode _closest_ ini, kalau dari MDN docs penjelasannya sebagai berikut :

> The closest() method of the Element interface traverses the element and its parents (heading toward the document root) until it finds a node that matches the specified CSS selector. Return value : the closest ancestor Element or itself, which matches the selectors. If there are no such element, null.

Jadi penjelasan singkatnya metode _closest_ mencari keatas (parent/anchestor) sampai menemukan selector yang dicari atau dirinya sendiri

```javascript
// app.js

menu.addEventListener('mouseover', (e) => {
  if (e.target.classList.contains('link')) {

    // menentukan target
    const link = e.target;

    // menentukan menu lain selain target
    const siblings = link.closest('.menu').querySelectorAll('.link');

    // jika menu lain bukan target (tidak terkena mouseover) maka opacity diset 0.2
    siblings.forEach((el) => {
      if (el !== link) el.style.opacity = 0.2;
    });
  }
});

menu.addEventListener('mouseout', (e) => {
  if (e.target.classList.contains('link')) {
    const link = e.target;
    const siblings = link.closest('.menu').querySelectorAll('.link');

    siblings.forEach((el) => {
      if (el !== link) el.style.opacity = 1;
    });
  }
});
```
Hasilnya

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

**Cara kedua**

Kita akan mencoba me-refactor kode diatas supaya lebih rapi karena ada kode yang berulang (rekursif). Untuk refactor kita buat fungsi baru

```javascript

// refactor
const handleOver = function (e, opacity) {
  if (e.target.classList.contains('link')) {
    const link = e.target;
    const siblings = link.closest('.menu').querySelectorAll('.link');

    siblings.forEach((el) => {
      if (el !== link) el.style.opacity = opacity;
    });
  }
};

menu.addEventListener('mouseover', handleOver(e, 0.5));
menu.addEventListener('mouseout', handleOver(e, 1));

```
Kode diatas akan menghasilkan error sebagai berikut

![file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fj0cvd91fzszuoal12mh.png)

Kenapa ? Karena metode addEventListener memerlukan sebuah fungsi untuk parameter keduanya, bukan sembarang variabel. Maka kita akan mem-passing fungsi sebagai berikut (hasilnya sama dengan diatas jadi saya tidak akan memperlihatkan)

```javascript

const menu = document.querySelector('.menu');
menu.addEventListener('mouseover', function (e) {
  handleOver(e, 0.2);
});

menu.addEventListener('mouseout', function (e) {
  handleOver(e, 1);
});
```

**Cara ketiga**

Cara terakhir kita akan menggunakan bind method yang juga pernah kita bahas [disini](https://dev.to/boibolang/call-apply-bind-javascript-167k). Bind method akan mengembalikan (return) fungsi yang dengan atribut/keyword 'this' yang bisa diisi nilai apapun

```javascript

const handleOver = function (e) {
  if (e.target.classList.contains('link')) {
    const link = e.target;
    const siblings = link.closest('.menu').querySelectorAll('.link');

    siblings.forEach((el) => {
      if (el !== link) el.style.opacity = this;
    });
  }
};
menu.addEventListener('mouseover', handleOver.bind(0.2));
menu.addEventListener('mouseout', handleOver.bind(1));

```
Argument pada bind hanya bisa diisi single value, apabila membutuhkan lebih bisa passing data berupa array