Topbar navigasi yang tetap terlihat ketika halaman digulir, banner persetujuan cookie di sudut bawah, dan tombol “kembali ke atas” memiliki kesamaan: ketiganya bertahan di tempat sekalipun konten bergerak. Perilaku itu berasal dari position bernilai fixed. Elemen fixed berpatokan pada viewport — jendela browser itu sendiri — sehingga menggulir dokumen tidak menggerakkannya sedikit pun. Pada Chapter ini kita membuat topbar dan banner cookie, lalu menelusuri satu gotcha yang terkenal: ancestor ber-transform yang diam-diam mencuri kendali atas elemen fixed.

Berpatokan pada Viewport #

Elemen fixed dikeluarkan dari alur dokumen, sama seperti absolute. Perbedaannya pada pilihan acuan: bukan ancestor positioned, melainkan initial containing block — kotak seukuran viewport yang titik nolnya berada di pojok kiri atas jendela. Offset top, right, bottom, dan left diukur dari tepi viewport, dan nilai itu tetap berlaku berapa pun posisi gulir halaman.

Karena keluar dari alur, elemen fixed tanpa width menyusut mengikuti lebar kontennya. Topbar selebar jendela dibuat dengan mengunci dua sisi sekaligus, misalnya left: 0; right: 0, sehingga lebar terisi penuh secara otomatis. Pola yang sama berlaku untuk panel samping atau banner: kunci sisi yang diinginkan, biarkan sisi lain bebas.

Kedudukan fixed terhadap posisi gulir juga berdampak pada urutan menggambar. Beberapa elemen fixed berada bersama di context akar sehingga urutan DOM memutuskan siapa yang menutupi; beri z-index bila urutan itu perlu dipaksa. Perlu diingat pula bahwa fixed selalu terlihat di seluruh gulungan halaman — bila elemen hanya perlu menempel pada bagian tertentu, sticky pada Chapter Sticky Positioning adalah pilihan yang lebih tepat.

Demo chapter ini menyediakan halaman panjang yang dapat digulir, lengkap dengan topbar tetap di atas, banner cookie di kanan bawah, dan satu eksperimen transform di dalamnya. Berikut CSS intinya:

css
.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 56px;
}
.banner-cookie {
  position: fixed;
  bottom: 16px;
  right: 16px;
  width: 320px;
}
html index.html
<header class="topbar">Toko Contoh — Navigasi</header>
<main>
  <!-- konten panjang yang dapat digulir -->
</main>
<aside class="banner-cookie">
  Kami memakai cookie fiktif untuk demo.
  <button>Setuju</button>
</aside>

Hasil di Browser:

text
Topbar menempel di tepi atas viewport: computed position: fixed,
top: 0px, left: 0px, height: 56px. Banner cookie menempel di kanan
bawah (computed bottom: 16px, right: 16px) dengan lebar tetap
320px. Ketika halaman digulir, keduanya tidak bergerak karena
acuannya adalah viewport, bukan dokumen.

Mari kita telaah aturan di atas baris demi baris:

  1. Baris 2–4 (position: fixed + top: 0 + left: 0): tepi atas dan kiri topbar dilekatkan ke tepi viewport. Ditambah right: 0, lebar topbar otomatis penuh.
  2. Baris 5 (height: 56px): tinggi tetap membantu kita menghitung padding-top konten agar tidak tertutup.
  3. Baris 8–11 (banner): bottom: 16px dan right: 16px memberi jarak 16px dari tepi bawah dan kanan viewport — pola khas banner cookie.
  4. Baris 12 (width: 320px): lebar eksplisit mencegah banner menyusut mengikuti teks, karena elemen fixed tidak lagi mengisi lebar alur.

Gotcha: Transform pada Ancestor #

Eksperimen pada demo memperlihatkan perilaku yang mengejutkan. Sebuah tombol diberi position: fixed; bottom: 0; right: 0, tetapi tombol itu menempel di sudut sebuah kartu, bukan di sudut viewport. Penyebabnya satu deklarasi: kartu induknya memiliki transform: translateY(1px). Transform selain none membuat ancestor tersebut menjadi containing block bagi semua keturunan fixed di dalamnya.

Aturan praktisnya: jaga rantai ancestor elemen fixed bebas dari properti-properti tersebut. Dokumentasi position di MDN merinci daftar properti pembentuk containing block ini bila Anda perlu menelusuri kasus yang lebih spesifik.