Halo semua, 2 bulan ini absen posting dikarenakan kesibukan yang padat. Mari kita mulai belajar lagi seputar JavaScript dan CSS, kali ini kita akan membahas dan membuat sticky element. Sticky element paling sering kita temukan pada navigation bar sebuah website, ada banyak cara untuk membuat sticky element, pada postingan kali ini kita akan membuat dengan 2 cara berbeda. Langsung saja kita buat file index.html, app.js dan style.css
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sticky Navigation</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<header>
<div class="nav">
<div class="logo">LOGO</div>
<ul class="menu">
<li><a href="#" class="section-1">Section 1</a></li>
<li><a href="#" class="section-2">Section 2</a></li>
<li><a href="#" class="section-3">Section 3</a></li>
<li><a href="#" class="section-4">Section 4</a></li>
</ul>
</div>
<div class="title">
<h1>This is header</h1>
</div>
</header>
<section class="section" id="section-1">This is section 1</section>
<section class="section" id="section-2">This is section 2</section>
<section class="section" id="section-3">This is section 3</section>
<section class="section" id="section-4">This is section 4</section>
<script src="app.js"></script>
</body>
</html>
style.css
/* file: style.css */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.title {
height: 900px;
background-color: cornflowerblue;
}
.nav {
height: 50px;
width: 100%;
background-color: aqua;
display: flex;
justify-content: space-between;
align-items: center;
font-weight: bold;
}
.nav .logo {
padding-left: 20px;
}
.nav ul {
display: flex;
}
.nav ul li {
list-style: none;
padding-right: 20px;
}
.nav ul li a {
text-decoration: none;
}
.section {
height: 900px;
font-size: 50px;
}
.section:nth-child(odd) {
background-color: greenyellow;
}
.section:nth-child(even) {
background-color: burlywood;
}
.nav.sticky {
position: fixed;
}
Sticky Element Cara Pertama
Kita isi dulu file app.js dengan implementasi smooth scrolling pada materi yang pernah kita bahas disini
// file: app.js
const selectors = {
linkSection1: document.querySelector('.section-1'),
linkSection2: document.querySelector('.section-2'),
linkSection3: document.querySelector('.section-3'),
linkSection4: document.querySelector('.section-4'),
section1: document.querySelector('#section-1'),
section2: document.querySelector('#section-2'),
section3: document.querySelector('#section-3'),
section4: document.querySelector('#section-4'),
navbar: document.querySelector('.nav'),
};
// Smooth scrolling
selectors.linkSection1.addEventListener('click', () => {
selectors.section1.scrollIntoView({ behavior: 'smooth' });
});
selectors.linkSection2.addEventListener('click', () => {
selectors.section2.scrollIntoView({ behavior: 'smooth' });
});
selectors.linkSection3.addEventListener('click', () => {
selectors.section3.scrollIntoView({ behavior: 'smooth' });
});
selectors.linkSection4.addEventListener('click', () => {
selectors.section4.scrollIntoView({ behavior: 'smooth' });
});
Hasilnya kurang lebih sebagai berikut
Kita ingin pada saat masuk ke Section 1 dan seterusnya, navigation bar-nya muncul. Kurang lebih logic-nya sebagai berikut :
- Dapatkan koordinat atas (top) Section 1 terhadap koordinat window
- Jika koordinat window lebih dari koordinat atas (top) Section 1 maka munculkan navigation bar
Mari kita implementasikan pada file app.js
// Sticky navbar cara pertama
// 1. Sticky navigation muncul pada saat section 1 tampil, maka harus kita dapatkan koordinat Y section 1
const section1Coord = selectors.section1.getBoundingClientRect();
console.log('Section 1 top:', section1Coord.top);
// 2.Jika tampilan koordinat Y window lebih dari koordinat Y section 1 maka sticky nav muncul
window.addEventListener('scroll', () => {
console.log(window.scrollY);
if (window.scrollY > section1Coord.top) selectors.navbar.classList.add('sticky');
else selectors.navbar.classList.remove('sticky');
});
Jika kita inspect halaman, berapa sih koordinat atas (top) section 1 sebenarnya ? Dari kode diatas didapatkan bahwa jarak atas (top) Section 1 terhadap window adalah 950 pixel. Hal ini sebenarnya bisa kita hitung dari tinggi header (900 px) + tinggi navigation bar (50 px).
Maka dengan logic diatas jika window scroll lebih dari 950 pixel maka navigation bar akan muncul, hasilnya sebagai berikut
Metode ini tidak cocok dipakai untuk skala besar karena scroll akan aktif terus menerus selama halaman diakses, dapat menyebabkan performance issue.
Sticky Element Dengan Intersection Observer API
Apa pula itu Intersection Observer API ? Berikut penjelasan dari website MDN
The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport.
Penjelasan singkatnya adalah intersection observer API akan memonitor posisi target terhadap posisi dokumen. Prakteknya seperti apa ? Mari kita bahas.
Syntax intersection observer API adalah sebagai berikut
const observer = new IntersectionObserver(obsCallback, obsOptions)
.
opsCallback adalah fungsi/callback yang akan dieksekusi, sedangkan obsOptions adalah parameter yang digunakan.
obsOptions memiliki beberapa parameter
obsOptions = {
root: 0,
threshold: 0.1,
rootMargin: '-50px'
}
root : adalah posisi dimana intersection dengan target terjadi, jika diisi dengan null artinya terhadap top-level viewport
threshold : adalah kapan akan muncul aksinya, bisa diisi dengan nilai tungal (dalam %) atau array. Jika kita isi 0.1 (sama dengan 10%) maka aksi akan muncul pada jarak 10% pada saat intersection terjadi atau 10% sebelum intersection berakhir
rootMargin : adalah batas (atas-bawah : height) dari element yang beririsan
Lengkapnya seperti ini
// Sticky navbar menggunakan intersection observer API
const obsCallback = (entries) => {
entries.forEach((entry) => {
console.log(entry);
});
};
const obsOption = {
root: null,
threshold: 0.1,
rootMargin: '-50px',
};
const observer = new IntersectionObserver(obsCallback, obsOption);
observer.observe(selectors.section1);
Perhatikan posisi berikut
Pada saat Section 1 masuk viewport sebesar 0.1 viewport, observer akan mendeteksi. Property yang penting untuk diingat adalah isIntersection dan intersectionRatio, pada console nilainya adalah true (isIntersection) dan 0.10105444490909576 (intersectionRatio). Jika kita scroll terus sebelum Section 1 habis sebesar 0.1 viewport, observer akan mendeteksi perubahan tapi kali ini nilai dari isIntersection adalah false dan intersectionRatio adalah 0.09617595374584198
Logic untuk implementasi kira-kira seperti ini
Kapan kita ingin navigation bar muncul ? Pada saat header sudah tidak terlihat, ini berarti property isIntersection bernilai false
// Sticky navigation bar menggunakan Intersection Observer API
const header = document.querySelector('header');
const navHeight = selectors.navbar.getBoundingClientRect().height;
const stickyNav = (entries) => {
const [entry] = entries;
if (!entry.isIntersecting) selectors.navbar.classList.add('sticky');
else selectors.navbar.classList.remove('sticky');
};
const headerObserver = new IntersectionObserver(stickyNav, {
root: null,
threshold: 0,
rootMargin: `-${navHeight}px`,
});
headerObserver.observe(header);
Hasilnya sebagai berikut
Note : console log untuk intersection observer gambarnya kurang jelas, bisa dicoba sendiri di browser masing-masing
Top comments (0)