Cara Membuat Navbar Responsif CSS

navbar adalah komponen pertama yang saya pelajari saat mulai bikin website, dan sampai sekarang masih menjadi bagian yang paling sering saya kerjakan ulang. pola di artikel ini (hamburger menu + media query) adalah pola yang selalu saya pakai, baik untuk project pribadi maupun project klien. untuk pondasi layout, pastikan sudah paham flexbox dan grid dan cara menggabungkan HTML dan CSS dulu.
1. struktur HTML
<nav class="navbar">
<div class="nav-container">
<a href="#" class="logo">MyBrand</a>
<button class="hamburger" id="hamburger" aria-label="Buka menu" aria-expanded="false">
<span></span>
<span></span>
<span></span>
</button>
<ul class="nav-menu" id="nav-menu">
<li><a href="#" class="active">Home</a></li>
<li><a href="#">Tutorial</a></li>
<li class="has-dropdown">
<a href="#">Blog</a>
<ul class="dropdown">
<li><a href="#">HTML/CSS</a></li>
<li><a href="#">JavaScript</a></li>
<li><a href="#">PHP</a></li>
<li><a href="#">Python</a></li>
</ul>
</li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div>
</nav>
penjelasan per bagian:
<nav class="navbar">: semantic HTML untuk navigasi utama.<div class="nav-container">: wrapper untuk center content dengan max-width.<a class="logo">: link logo. biasanya link ke homepage.<button class="hamburger">: tombol toggle menu di mobile. pakai<button>bukan<div>karena semantic + accessible.aria-label="Buku menu": untuk screen reader. tanpa ini, tombol cuma berisi garis tanpa label.aria-expanded="false": state apakah menu terbuka. di-toggle via JavaScript.<span>tiga baris di dalam hamburger : untuk icon hamburger (3 garis) yang bisa di-animasikan jadi X.<ul class="nav-menu">: list menu utama.<li class="has-dropdown">: parent untuk dropdown.<ul class="dropdown">: sub-menu untuk dropdown.
2. CSS dasar (desktop)
* { margin: 0; padding: 0; box-sizing: border-box; }
.navbar {
background: #1e293b;
padding: 1rem 0;
position: sticky;
top: 0;
z-index: 1000;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.nav-container {
max-width: 1200px;
margin: auto;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
}
.logo {
color: white;
font-size: 1.5rem;
text-decoration: none;
font-weight: bold;
}
.nav-menu {
list-style: none;
display: flex;
gap: 1rem;
}
.nav-menu a {
color: white;
text-decoration: none;
padding: 0.5rem 1rem;
border-radius: 5px;
transition: background 0.3s ease;
}
.nav-menu a:hover, .nav-menu .active {
background: #334155;
}
.hamburger {
display: none;
background: none;
border: none;
cursor: pointer;
padding: 0.5rem;
}
.hamburger span {
display: block;
width: 25px;
height: 3px;
background: white;
margin: 5px 0;
border-radius: 3px;
transition: all 0.3s ease;
}
penjelasan property penting:
position: sticky; top: 0: navbar tetap di atas saat di-scroll.stickylebih baik darifixedkarena tidak overlap konten.z-index: 1000: pastikan navbar di atas elemen lain.box-shadow: efek elevasi subtle.display: flex; gap: 1rem: flexbox untuk layout horizontal dengan gap otomatis.transition: background 0.3s ease: animasi smooth saat hover..hamburgerdidisplay: nonedi desktop, baru muncul di mobile.
3. dropdown CSS (multi-level)
.has-dropdown {
position: relative;
}
.dropdown {
list-style: none;
position: absolute;
top: 100%;
left: 0;
background: #1e293b;
min-width: 200px;
display: none;
flex-direction: column;
border-radius: 5px;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
margin-top: 0.5rem;
padding: 0.5rem 0;
}
.has-dropdown:hover .dropdown,
.has-dropdown:focus-within .dropdown {
display: flex;
}
.dropdown li {
width: 100%;
}
.dropdown a {
display: block;
padding: 0.75rem 1.5rem;
border-radius: 0;
}
.dropdown a:hover {
background: #334155;
}
penjelasan:
position: relativedi parent : supayaposition: absolutedi child relative ke sini.top: 100%: dropdown muncul tepat di bawah parent.display: nonedefault, jadi tersembunyi.:hoverdan:focus-within: show dropdown saat hover atau focus.:focus-withinpenting untuk keyboard navigation.min-width: 200px: lebar minimum dropdown supaya konsisten walau item pendek.
4. CSS mobile (hamburger aktif)
/* Tablet ke bawah */
@media (max-width: 768px) {
.hamburger {
display: block;
}
.nav-menu {
display: none;
flex-direction: column;
position: absolute;
top: 100%;
left: 0;
right: 0;
background: #1e293b;
padding: 1rem 0;
gap: 0;
}
.nav-menu.active {
display: flex;
}
.nav-menu li {
width: 100%;
}
.nav-menu a {
display: block;
padding: 1rem 20px;
border-radius: 0;
}
/* Dropdown jadi inline di mobile */
.dropdown {
position: static;
background: rgba(0,0,0,0.2);
box-shadow: none;
margin-top: 0;
}
.has-dropdown:hover .dropdown,
.has-dropdown:focus-within .dropdown {
display: none; /* nonaktifkan hover di mobile */
}
.has-dropdown.open .dropdown {
display: flex; /* toggle via class 'open' di mobile */
}
}
5. JavaScript untuk toggle
const hamburger = document.getElementById('hamburger');
const navMenu = document.getElementById('nav-menu');
// Toggle menu
hamburger.addEventListener('click', () => {
navMenu.classList.toggle('active');
hamburger.classList.toggle('active');
const isExpanded = hamburger.getAttribute('aria-expanded') === 'true';
hamburger.setAttribute('aria-expanded', !isExpanded);
hamburger.setAttribute('aria-label', !isExpanded ? 'Tutup menu' : 'Buka menu');
});
// Tutup menu saat klik di luar
document.addEventListener('click', (e) => {
if (!e.target.closest('.navbar')) {
navMenu.classList.remove('active');
hamburger.classList.remove('active');
hamburger.setAttribute('aria-expanded', 'false');
}
});
// Tutup menu saat resize ke desktop
window.addEventListener('resize', () => {
if (window.innerWidth > 768) {
navMenu.classList.remove('active');
hamburger.classList.remove('active');
}
});
// Dropdown toggle di mobile
document.querySelectorAll('.has-dropdown > a').forEach(link => {
link.addEventListener('click', (e) => {
if (window.innerWidth <= 768) {
e.preventDefault();
link.parentElement.classList.toggle('open');
}
});
});
penjelasan per bagian:
classList.toggle('active'): tambah/hapus class ‘active’. CSS@media (max-width: 768px)punya rule.nav-menu.active { display: flex; }untuk show menu.aria-expandeddi-toggletrue/falseuntuk screen reader.aria-labeldi-update sesuai state (Buka/Tutup menu).- Klik di luar
.navbarakan tutup menu (UX pattern umum). - Resize listener bersihkan state saat user rotate phone atau resize window.
- Dropdown di mobile jadi accordion (klik toggle), bukan hover (karena tidak ada hover di touch device).
6. animasi hamburger jadi X
trik bikin hamburger icon jadi X saat menu terbuka:
.hamburger.active span:nth-child(1) {
transform: translateY(8px) rotate(45deg);
}
.hamburger.active span:nth-child(2) {
opacity: 0;
}
.hamburger.active span:nth-child(3) {
transform: translateY(-8px) rotate(-45deg);
}
3 baris span di-translate + rotate jadi bentuk X saat class .active ditambah. smooth karena pakai transition.
7. navbar dengan scroll effect
navbar yang shrink/ubah style saat user scroll ke bawah:
let lastScroll = 0;
const navbar = document.querySelector('.navbar');
window.addEventListener('scroll', () => {
const currentScroll = window.pageYOffset;
// Sembunyikan saat scroll down, tampil saat scroll up
if (currentScroll > lastScroll && currentScroll > 100) {
navbar.classList.add('hidden');
} else {
navbar.classList.remove('hidden');
}
// Tambah shadow saat scroll
if (currentScroll > 50) {
navbar.classList.add('scrolled');
} else {
navbar.classList.remove('scrolled');
}
lastScroll = currentScroll;
});
.navbar {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.navbar.hidden {
transform: translateY(-100%);
}
.navbar.scrolled {
background: rgba(30, 41, 59, 0.95);
backdrop-filter: blur(10px);
}
backdrop-filter: blur(10px) bikin efek frosted glass, modern.
8. dark mode support
kalau blog kamu support dark mode, tambahkan preferensi:
@media (prefers-color-scheme: dark) {
.navbar {
background: #0f172a;
}
.nav-menu a:hover, .nav-menu .active {
background: #1e293b;
}
}
prefers-color-scheme: dark adalah media query yang detect preferensi OS user. otomatis apply tanpa JavaScript.
9. checklist aksesibilitas (a11y)
- semantic HTML: pakai
<nav>untuk navbar,<button>untuk hamburger,<ul>/<li>untuk list menu. - aria-label di hamburger button: “Buka menu” / “Tutup menu”.
- aria-expanded untuk state:
truesaat terbuka,falsesaat tertutup. - aria-current=“page” di menu item yang aktif:
aria-current="page". - focus visible untuk keyboard navigation: jangan
outline: nonetanpa pengganti. - skip to content link untuk screen reader:
<a href="#main" class="skip-link">Skip to content</a>. - kontras warna minimal 4.5:1 (WCAG AA). test dengan WebAIM Contrast Checker.
- touch target minimal 44x44px untuk mobile (Apple HIG).
10. tips produksi
- mobile-first approach: tulis CSS untuk mobile dulu, tambah media query
(min-width)untuk desktop. lebih mudah dan lebih cepet di mobile. - transform/opacity untuk animasi (GPU-accelerated), hindari animasi
width/height/top/left. - throttle scroll event dengan
requestAnimationFrameuntuk performa. - test di device asli bukan cuma Chrome DevTools. DevTools tidak 100% akurat untuk touch behavior.
- hamburger tidak harus di kiri : bisa di kanan, atau bahkan ganti icon (3 titik vertikal, grid 9 titik). yang penting konsisten dengan design system.
- sticky navbar dengan
position: stickylebih SEO-friendly darifixedkarena tidak ada masalah layout shift. - z-index management: pakai scale (10, 100, 1000) untuk atur layering, jangan random.
- Hapus tap delay 300ms dengan
<meta name="viewport" content="width=device-width">atautouch-action: manipulationdi CSS. - test cross-browser di Safari iOS (punya quirk sendiri, terutama
100vhdansticky). - performance budget: navbar < 14KB (HTML + CSS + JS combined) untuk fast first paint.
11. update 2025-2026: navbar tanpa banyak JS
tahun ini banyak fitur CSS yang dulu harus pakai JavaScript sekarang sudah baseline. kalau kalian bikin navbar baru di 2026, pertimbangkan ini:
Container Queries: navbar responsif terhadap parent, bukan viewport
Media query pakai lebar viewport. Container Query pakai lebar parent. berguna kalau navbar dipakai sebagai komponen di sidebar sempit vs halaman lebar.
.nav-wrapper { container-type: inline-size; container-name: navbar; }
@container navbar (max-width: 600px) {
.nav-menu { flex-direction: column; }
.hamburger { display: block; }
}
Support 2026: Chrome 105+, Firefox 110+, Safari 16+ (baseline). Bungkus pakai @supports (container-type: inline-size) untuk fallback ke media query lama.
:has() — parent selector buat state tanpa JS
:has() sudah baseline 2023. Contoh yang kepake di navbar:
/* lock scroll body kalau menu terbuka, tanpa JS tambah class ke body */
body:has(.nav-menu.active) { overflow: hidden; }
/* highlight parent kalau dropdown-nya punya focus */
.has-dropdown:has(:focus-visible) { outline: 2px solid currentColor; }
/* disable tombol submit kalau form di navbar invalid */
form:has(input:invalid) .submit-btn { opacity: .5; pointer-events: none; }
Popover API + CSS Anchor Positioning: dropdown tanpa JS
Kombinasi 2024-2025 yang paling mengubah cara bikin dropdown. Popover handle buka/tutup + top-layer + ESC + klik luar. Anchor Positioning handle posisi dropdown relatif ke tombol tanpa getBoundingClientRect().
<button id="btn-blog" popovertarget="menu-blog">Blog ▾</button>
<ul id="menu-blog" popover class="dropdown">
<li><a href="#">HTML/CSS</a></li>
<li><a href="#">JavaScript</a></li>
</ul>
#btn-blog { anchor-name: --btn-blog; }
#menu-blog {
position: absolute;
position-anchor: --btn-blog;
position-area: bottom span-right;
position-try-fallbacks: flip-block, flip-inline;
margin: 0;
width: anchor-size(width);
}
position-try-fallbacks: flip-block otomatis pindah ke atas kalau mentok bawah viewport, tanpa JS. Popover sudah baseline Januari 2025, Anchor Positioning Chrome 125+ (Mei 2024) dan Safari 26 (Sep 2025), Firefox Nightly progress 2026. Untuk fallback, biarkan dropdown jadi position: absolute; top: 100% biasa, bungkus anchor rules di @supports (position-anchor: --a).
View Transitions & Scroll-driven Animations
Kalau mau transisi halus antar halaman atau animasi navbar saat scroll, 2026 ada View Transitions API (same-document baseline, cross-document di Chrome) dan animation-timeline: scroll() untuk shrink navbar tanpa listener scroll. Untuk sekarang, tetap throttle scroll + transform sebagai baseline, tambah animation-timeline sebagai progressive enhancement.
CSS Nesting & @layer
Nesting sudah stabil 2023, bikin navbar CSS lebih rapi tanpa Sass:
.navbar {
background: #1e293b;
& .nav-menu { display: flex; }
& .hamburger { display: none; }
}
@layer bantu urutkan reset / components / utilities tanpa perang !important.
Kesimpulan
- HTML semantic + flexbox + media query adalah pondasi navbar responsif modern
- sticky lebih baik dari fixed (no layout shift, SEO-friendly)
- dropdown pakai
:hover(desktop) atau accordion (mobile) - hamburger icon animasi dari 3 garis jadi X pakai
transform: rotate - scroll effect dengan
backdrop-filter: blur()untuk frosted glass modern - aksesibilitas wajib: ARIA, semantic HTML, keyboard nav, kontras warna
- performance: mobile-first, transform/opacity untuk animasi, throttle scroll
untuk versi lebih advance, pertimbangkan pakai Tailwind CSS dengan component library seperti DaisyUI atau Flowbite. mereka sudah handle responsive + a11y + dark mode out of the box.
Baca Juga Mengenai :
Pertanyaan yang Sering Diajukan
Apa itu navbar responsif?
navbar yang layout-nya berubah mengikuti ukuran layar. di desktop tampil horizontal dengan menu lengkap, di mobile jadi hamburger button yang bisa buka-tutup menu secara vertikal. wajib untuk UX modern karena mayoritas traffic sekarang dari mobile.
Kapan pakai hamburger menu vs menu horizontal?
hamburger untuk mobile (layar < 768px), menu horizontal untuk desktop (>= 768px). breakpoint umum 768px (tablet) atau 1024px (laptop kecil). untuk project serius, breakpoint ideal di-set per device.
Apa beda navbar sticky dan fixed?
sticky = posisi relatif tapi "menempel" saat user scroll lewat, default posisi di flow normal. fixed = posisi absolute di viewport, selalu kelihatan walau di-scroll. sticky lebih umum karena tidak overlap konten.
Bagaimana cara bikin navbar tanpa JavaScript?
pakai checkbox hack: input type=checkbox tersembunyi + label, klik label toggle menu via CSS sibling selector (~). tapi untuk hamburger button di mobile, JavaScript tetap paling simpel dan accessible.
Apa itu aria-label dan kenapa penting untuk navbar?
aria-label adalah atribut HTML untuk screen reader. pada hamburger button, tambahkan aria-label="Buka menu" supaya user dengan disabilities tahu fungsi tombol. juga pakai aria-expanded untuk state buka/tutup.
Bagaimana cara bikin dropdown di navbar?
struktur HTML nested: li > ul di dalam menu utama. CSS pakai :hover atau :focus-within untuk show dropdown. untuk mobile, dropdown biasanya jadi accordion (klik buka, bukan hover).
Berapa breakpoint yang ideal untuk navbar?
umum: 768px (mobile ke tablet), 1024px (tablet ke laptop). untuk project serius, pakai 3 breakpoint: 480px (hp kecil), 768px (tablet), 1024px (laptop). breakpoint dipilih dari analisis traffic, bukan asal.
Bagaimana optimasi performa navbar?
CSS transform/opacity untuk animasi (GPU-accelerated, bukan top/left). backface-visibility: hidden untuk trigger composite layer. throttle event scroll untuk navbar sticky. lazy load gambar di menu.

