01 · Cara yang biasa
Kebanyakan header yang mengecil adalah scroll listener.
Dengarkan scroll, baca scrollY, pasang class atau state, lalu biarkan framework me-render ulang. Cara ini berhasil, tapi berjalan di main thread pada setiap event scroll. Di halaman yang sedang sibuk hydration, di situlah kamu tidak mau ada pekerjaan tambahan.
02 · Cara CSS
Ikat progres animasi ke posisi scroll, bukan ke waktu.
animation-timeline: scroll() menjadikan scroll halaman sebagai jamnya. animation-range menentukan di mana animasi mulai dan selesai. Di antara scroll 10vh dan 30vh, menu mendapat background dan bayangan, logo mengecil, dan tagline memudar. Trik yang sama menggerakkan efek parallax scale di hero selama 100vh pertama.
@keyframes stick-menu {
to { padding-block: 1rem; background: #fff; box-shadow: 0 8px 24px rgb(0 0 0 / 0.12); }
}
@keyframes shrink-logo {
to { width: 150px; transform: translate(0, 0.25rem); }
}
@supports (animation-timeline: scroll()) {
.menu {
animation: stick-menu 1ms linear forwards;
animation-timeline: scroll();
animation-range: 10vh 30vh;
}
.logo-full {
animation: shrink-logo 1ms linear forwards;
animation-timeline: scroll();
animation-range: 10vh 30vh;
}
}03 · Jebakan urutan
Tulis animation-timeline setelah shorthand animation.
Shorthand-nya me-reset animation-timeline ke nilai default. Kalau timeline ditulis duluan, shorthand diam-diam menghapusnya, dan header berhenti merespons scroll. Durasi 1ms hanya placeholder yang dibutuhkan shorthand. Yang menentukan progres adalah scroll, bukan waktu. forwards menahan kondisi akhir setelah kamu melewati rentangnya.
04 · Fallback-nya adalah kondisi akhir
Tidak didukung berarti tidak ada animasi, bukan polyfill JavaScript.
Di dalam @supports not (animation-timeline: scroll()), header yang beranimasi langsung mendapat nilai akhirnya: logo ringkas, background solid, tanpa tagline. Tampilannya seperti header setelah kamu scroll. Tidak ada yang rusak dan tidak ada yang dimuat tambahan.
@supports not (animation-timeline: scroll()) {
.menu.animated { padding-block: 1rem; background: #fff; box-shadow: 0 8px 24px rgb(0 0 0 / 0.12); }
.logo-full.animated { width: 150px; }
}05 · Yang akan saya tambahkan
Reduced motion.
Perubahan header mengikuti scroll kamu sendiri, jadi terasa seperti manipulasi langsung. Efek parallax scale di hero adalah jenis gerakan yang dimatikan sebagian orang, dan proyek itu belum mengeceknya. Lain kali saya akan membungkus parallax-nya dengan @media (prefers-reduced-motion: no-preference).
