Membuat Sticky Header Navigation Menggunakan jQuery Waypoints
() translation by (you can also view the original English article)
Dalam tutorial ini, kami akan membuat bilah navigasi yang tetap bersama Anda saat Anda menggulir ke bawah - dan kami juga akan melemparkan satu atau dua gimmick ke dalam campuran untuk menghilangkannya.
Setiap beberapa minggu, kami mengunjungi kembali beberapa posting favorit pembaca kami dari sepanjang sejarah situs. Tutorial ini pertama kali diterbitkan pada bulan Maret 2012.
Pengenalan
“Semua orang menyukai pita,” kata Chris Coyier ketika mendiskusikan keutamaan :before
dan :after
elemen semu. Saya telah melihat pita-pita di styling bermata segitiga ini bermunculan di seluruh Internet (salah satu contoh yang menonjol adalah halaman Introducing Timeline Facebook) dan, sementara mereka memiliki daya tarik tertentu, saya harus mengakui bahwa efek spasial yang mereka buat tidak terjadi. tidak terlihat benar bagiku.



Pita disukai karena suatu alasan - mereka merusak sebagian besar paradigma desain datar yang secara tradisional kita terikat, dan mereka adalah salah satu dari sedikit elemen visual yang melakukannya dengan cara yang tidak mencolok. Tapi, seperti kata pepatah kuno, seharusnya ada lebih dari satu cara untuk menguliti kucing - jadi, dalam tutorial ini, saya akan mengusulkan gaya visual alternatif untuk elemen-elemen semacam itu, yang menurut saya jauh lebih alami dan estetis. menyenangkan. Saya harap Anda menyukainya dan memanfaatkannya dengan baik!
Apa Yang Akan Kami Lakukan
Dalam tutorial ini, kita akan menggunakan salah satu elemen baru di HTML5, nav
tag, sebagai wadah untuk daftar horisontal link. Saya akan menjelaskan secara singkat bagaimana membuatnya terlihat cantik menggunakan sedikit CSS.
Yang paling penting, Anda akan terbiasa dengan dasar-dasar plugin Waypoints jQuery, yang akan memberikan fungsionalitas canggih: saat pengguna menggulir ke bawah, bilah navigasi akan menempel di bagian atas viewport, serta mengubah untuk menunjukkan bagian saat ini . Sebagai sedikit sentuhan tambahan, kita akan menggunakan plugin lain, ScrollTo, untuk memberikan bergulir halus dan nyaman posisi ketika pengguna mengklik pada link navigasi.
Langkah 1: Kotak
Saya yakin Anda sudah akrab dengan berbagai elemen baru yang telah diperkenalkan dengan HTML5. Dalam contoh ini kita akan membuat menggunakan dua di antaranya: <nav>
dan <section>
. Kita akan mulai dengan berikut:
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
<head>
|
4 |
<meta charset="UTF-8" /> |
5 |
<link rel="stylesheet" href="styles.css" /> |
6 |
</head>
|
7 |
<body>
|
8 |
<div class=wrapper> |
9 |
<h1>A reasonably large heading.</h1> |
10 |
<nav><!-- Navigation. --></nav> |
11 |
<section id="section-1">Lorem ipsum ...</section> |
12 |
<!-- Type in some longer sections of sample text here. -->
|
13 |
</div>
|
14 |
<!-- Scripts will go here. -->
|
15 |
</body>
|
16 |
</html>
|
Kita akan harus memberikan bar navigasi kita lebar eksplisit. Buat 28px lebih lebar dari pembungkus, dan sorong ke tempatnya dengan margin kiri negatif. Mari kita juga memberikannya ujung atas bulat lembut menggunakan border-*-radius
, serta beberapa padding sewenang-wenang.
1 |
nav { |
2 |
position: relative; |
3 |
width: 928px; |
4 |
padding: 2em; |
5 |
margin-left: -14px; |
6 |
border-top-left-radius: 14px 7px; |
7 |
border-top-right-radius: 14px 7px; |
8 |
}
|
Selanjutnya, kami akan menambahkan daftar unordered link dalam bilah navigasi, dan mengatur item untuk display: inline-block
untuk menempatkan mereka semua pada satu baris. Kami tidak membutuhkan bullets, jadi kami juga akan melempar list-style: none
ada ke dalam campuran.
1 |
<nav>
|
2 |
<ul>
|
3 |
<li><a class=nav-link href=#section-1>Section 1</a></li> |
4 |
<li><a class=nav-link href=#section-2>Section 2</a></li> |
5 |
...some more list items... |
6 |
</ul>
|
7 |
</nav>
|
1 |
nav li { |
2 |
display: inline-block; |
3 |
list-style: none; |
4 |
}
|
Sampai sekarang, Anda harus memiliki sesuatu seperti ini:



Langkah 2: Tepi
Sekarang, jika hanya CSS memungkinkan kita untuk memiliki beberapa unsur-unsur pseudo (yaitu:: after::after
), kita bisa dengan mudah menyelesaikan tepi bulat bar navigasi dalam cara yang semantik clean way. Tapi kita tidak bisa melakukan itu, jadi kita harus menambahkan dua non-semantik div
s pada akhir nav
. Memberi mereka kelas nav-left
dan kanan-right
(atau Anda dapat memanggil mereka sesuatu yang imajinatif, seperti Castor dan Pollux). Mereka 14px lebar dengan 14px tinggi, dan benar-benar
diposisikan 14px dari ujung bawah nav
.
Seperti yang terlihat di atas, border-radius
family properties dapat mengambil dua nilai untuk setiap sudut. Mereka juga dapat persentase elemen lebar, yang cukup berguna-pendekatan ini memungkinkan radius perbatasan untuk secara otomatis beradaptasi dengan perubahan dalam kotak dimensi.
'Bayangan' kecil yang melengkapi tampilan pita bilah navigasi dibuat menggunakan ::after
elemen semu. Mereka lebar dan tinggi, serta jari-jari perbatasan mereka, juga ditetapkan menggunakan persentase.
1 |
/* swap ‘left’ with ‘right’ for the other two */
|
2 |
|
3 |
.nav-left { |
4 |
position: absolute; |
5 |
left: 0; bottom: -14px; |
6 |
width: 14px; height: 14px; |
7 |
background: #848a6a; |
8 |
border-bottom-left-radius: 100% 50%; |
9 |
}
|
10 |
|
11 |
.nav-left::after { |
12 |
content: ''; |
13 |
position: absolute; |
14 |
right: 0; |
15 |
width: 66%; height: 66%; |
16 |
background: #000; |
17 |
border-top-left-radius: 100% 50%; |
18 |
border-bottom-left-radius: 100% 50%; |
19 |
}
|
Dan kita selesai di sini!



Memiliki menyingkirkan sebagian besar geometri mustahil pita bermata lurus, mari kita membawa.
Langkah 3: Script
Untuk mencapai efek tajuk mengambang, kami akan menggunakan plugin jQuery yang disebut Waypoints, oleh Caleb Troughton. Tujuannya hanya untuk memicu event ketika pengguna menggulir ke elemen tertentu. Seperti yang akan Anda lihat, ini sangat sederhana, namun menawarkan banyak fleksibilitas - Anda dapat melihat beberapa contoh di beranda.
Menyertakan jQuery dan Waypoints ke halaman Anda, dan mari kita mulai!
Pertama yang perlu Anda lakukan adalah mendaftarkan waypoint dengan memanggil .waypoint()
metode pada elemen. Tentu saja, ini tidak melakukan apa-apa dengan sendirinya - Anda harus mendefinisikan fungsi penangan untuk acara tersebut. Cara termudah untuk melakukan ini adalah dengan melewatkan fungsi itu sebagai parameter ke .waypoint()
.
Coba sekarang: tambahkan yang berikut ini ke skrip Anda dan lihat pesan yang muncul saat Anda menggulir melewati navigation bar.
1 |
$(function() { // When the page has loaded, |
2 |
$('nav').waypoint( // create a waypoint |
3 |
function() { |
4 |
alert("Waypoint reached."); |
5 |
} |
6 |
) |
7 |
}); |
Sekarang, untuk mencapai efek yang kita inginkan, segala sesuatunya akan menjadi sedikit lebih rumit. Pertama, kita perlu melampirkan nav bar kita dalam sebuah container, yang akan menjadi waypoint kita yang sebenarnya, dan berfungsi sebagai placeholder (lebih lanjut tentang ini di bawah ini).
1 |
<div class="nav-container"> |
2 |
<nav>
|
3 |
... |
4 |
</nav>
|
5 |
</div>
|
Dalam CSS Anda, membuat aturan CSS berikut. (Sementara Anda melakukannya, pindahkan margin vertikal apa pun yang mungkin dimiliki nav
ke nav-container
)
1 |
.sticky { |
2 |
position: fixed; |
3 |
top: 0; |
4 |
}
|
Dan kami siap untuk bagian yang baik! Ubah konten skrip Anda menjadi seperti berikut:
1 |
$(function() { |
2 |
|
3 |
// Do our DOM lookups beforehand |
4 |
var nav_container = $(".nav-container"); |
5 |
var nav = $("nav"); |
6 |
|
7 |
nav_container.waypoint({ |
8 |
handler: function(event, direction) { |
9 |
nav.toggleClass('sticky', direction=='down'); |
10 |
} |
11 |
}); |
12 |
|
13 |
}); |
Oke, dari mana semua ini berasal, Anda berhak bertanya. Nah, Anda mungkin mengetahui bahwa kita sedang memasang waypoint untuk nav-container
; hanya kali ini, kita melakukannya berbeda. Bukannya secara langsung lewat fungsi pengendali untuk .waypoint()
, Kami encapsulasi dalam objek. Dengan sendirinya, ini tidak membuat perbedaan: keduanya benar-benar berlaku cara melakukan hal yang sama. Objek yang kita parsing, dapat berisi beberapa nilai opsi lain - jadi menggunakannya sekarang membuat kode lebih konsisten nantinya.
Fungsi handler yang telah kami tetapkan menerima dua parameter: yang pertama adalah jQuery event
object standar, yang kurang menarik di sini. Yang kedua adalah Waypoints khusus: itu adalah string yang nilainya baik ‘down’
atau ‘up’
tergantung pada cara mana pengguna menggulir ketika mereka mencapai titik jalan.
Sekarang, mengetahui ke arah mana pengguna akan pergi adalah sedikit informasi yang sangat penting untuk dimiliki, hanya karena itu memungkinkan kita untuk menjalankan behavior yang berbeda di kedua arah. Dalam isi fungsi handler, kami menggunakan varian yang relatif sedikit diketahui dari jQuery .toggleClass()
method, yang membuat singkatan berguna: dalam sintaks ini, parameter kedua menentukan apakah kelas akan ditambahkan ke elemen target atau dihapus dari itu. Ketika pengguna menggulir ke bawah, expression direction==='down'
bernilai true
, sehingga nav bar kami menerima kelas sticky
, dan menempel ke bagian atas viewport. Segera setelah pengguna menggulir kembali, kelas dihapus dari bilah navigasi, yang kembali ke tempatnya. Mari kita coba.
Keren, ya? Namun, jika Anda perlahan-lahan gulir ke bawah melewati titik jalan yang baru saja Anda buat, Anda mungkin akan melihat bahwa ketika Anda menyebarkannya konten 'melompat' sedikit karena bilah navigasi dihapus dari content flow. Selain terlihat sangat ceroboh, perilaku seperti itu dapat mungkin mengaburkan bagian dari konten Anda dan merusak kegunaannya. Untungnya, yang diperlukan hanyalah perbaikan sederhana - menambahkan kode berikut ke fungsi handler Anda membuat lompatan hilang.
1 |
if (direction == 'down') |
2 |
nav_container.css({ 'height':nav.outerHeight() }); |
3 |
else |
4 |
nav_container.css({ 'height':'auto' }); |
Apa yang terjadi di sini cukup jelas: kita gunakan nav-container
sebagai placeholder, seperti disebutkan di atas. Saat kami menggulir ke bawah, kami memperluas tingginya, dan konten di bawah tetap ada. Namun, ada kemungkinan - agar ini berfungsi sebagaimana mestinya, setiap margin vertikal yang mungkin ingin Anda miliki di sekitar bilah navigasi harus diterapkan pada nav-container
dan bukan ke nav
.
Jadi begitulah! Kami mendapatkan sendiri navbar fixed yang bagus, seperti yang sudah dilakukan banyak situs lain. Pertunjukkan sudah berakhir, teman-teman ...
.. .atau itu? Nah, masih ada satu atau dua trik yang mungkin ingin Anda lihat, dan yang mungkin menempatkan Anda di depan paket. Jika ini kasusnya, Baca terus.
Langkah 4: Vertical Offsets
Jika Anda memikirkannya, ada banyak kasus di mana memicu suatu event ketika suatu elemen mencapai tepi viewport browser bukan apa yang ingin Anda lakukan. Untungnya, Waypoints menyediakan pilihan yang nyaman untuk itu: offset
. Begini codenya:
1 |
nav.waypoint( { |
2 |
handler: …, |
3 |
offset: 50 |
4 |
} ) |
offset
memungkinkan Anda untuk membuat waypoint sebenarnya pada jarak variabel dari atas element. Nilai positif memicu waypoint ketika bagian atas elemen berada pada jarak yang ditentukan di bawah bagian atas viewport, dan nilai negatif memicu viewport ketika elemen berada jauh di atas bagian atas viewport (yaitu pengguna telah menggulir melewatinya dengan baik). ).
Nilai offset dapat berupa angka (mewakili jumlah piksel tetap), string yang berisi persentase (ditafsirkan sebagai persentase tinggi viewport), atau fungsi yang mengembalikan sejumlah piksel. Yang terakhir dapat memberikan fleksibilitas serius, dan kami akan menggunakannya nanti. Untuk saat ini, mari kita berpegang teguh pada nilai-nilai tetap dan lihat apa manfaatnya.
Hal pertama yang terlintas dalam pikiran adalah menambahkan beberapa ruang di atas elemen sticky. Menggunakan variabel offset
, ini mudah: untuk offset 15-piksel dari atas, tambahkan offset: 15px
ke .waypoint()
options, dan ubah top: 0px
ke top: 15px
dalam .sticky
CSS rule.
Jika desain Anda memanggil untuk itu, gradien kecil di atas navbar juga bisa menjadi sentuhan yang bagus Hal ini mudah dicapai dengan menambahkan lagi div
di nav
, dan menulis sedikit CSS:
1 |
.sticky .nav-above { |
2 |
position: absolute; |
3 |
top:-15px; |
4 |
left:1em; |
5 |
right:1em; |
6 |
height:15px; |
7 |
background: linear-gradient(top, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); |
8 |
/* add cross-browser gradient code as needed */
|
9 |
}
|
Ini sedikit cukup halus eye candy akan bekerja dengan baik dalam desain minimalis.
Langkah 5: Offset Functions
Satu hal yang dipertimbangkan oleh Caleb dalam Waypoint adalah mampu menghasilkan offset waypoint secara dinamis, seperti:
1 |
nav.waypoint( { |
2 |
handler: …, |
3 |
offset: function() { |
4 |
return —(nav.outerHeight()+50); |
5 |
} |
6 |
} ) |
Hal ini memungkinkan kita untuk memiliki handler yang akan memicu ketika pengguna telah menggulir 50px melewati bagian bawah elemen, tanpa perlu mengetahui ketinggian sebelumnya.
Catatan: offset yang dihasilkan secara prosedural tersebut (dan juga yang diberikan sebagai persentase), dihitung ulang setiap kali ukuran jendela diubah, waypoint baru ditambahkan, atau opsi waypoint diubah. Jika Anda melakukan sesuatu yang lain yang dapat mempengaruhi posisi waypoints (seperti mengubah tata letak halaman atau DOM), pastikan untuk memanggil $.waypoints('refresh')
setelah itu untuk posisi yang akan dihitung ulang.
Dalam konteks tutorial kami, satu kegunaan untuk fungsi ini adalah dengan lancar menggeser bilah navigasi dari atas. Bersiaplah - berikut ini adalah potongan kode terbesar sejauh ini. Seharusnya tidak ada apa pun di dalamnya yang belum Anda kenal, jadi begini:
1 |
var top_spacing = 15; |
2 |
var waypoint_offset = 50; |
3 |
|
4 |
nav_container.waypoint({ |
5 |
|
6 |
handler: function(event, direction) { |
7 |
|
8 |
if (direction == 'down') { |
9 |
|
10 |
nav_container.css({ 'height' : nav.outerHeight() }); |
11 |
nav.addClass("sticky") |
12 |
.stop() |
13 |
.css("top", -nav.outerHeight()) |
14 |
.animate({"top" : top_spacing}); |
15 |
|
16 |
} else { |
17 |
|
18 |
nav_container.css({ 'height' : 'auto' }); |
19 |
nav.removeClass("sticky") |
20 |
.stop() |
21 |
.css("top", nav.outerHeight() + waypoint_offset) |
22 |
.animate({"top" : ""}); |
23 |
|
24 |
} |
25 |
|
26 |
}, |
27 |
|
28 |
offset: function() { |
29 |
return —(nav.outerHeight() + waypoint_offset); |
30 |
} |
31 |
|
32 |
}); |
Tidak terlalu buruk! Ini semua tarif jQuery standar yang cantik: segera setelah kami menambah atau menghapus kelas sticky
di nav
, kami menimpa posisi vertikal elemen menggunakan .css()
, dan kemudian .animate()
untuk apa yang seharusnya. .stop()
berfungsi untuk mencegah kemungkinan bug dengan menghapus antrian acara jQuery.
Namun, ada sedikit efek samping pada hal ini - karena kode secara efektif mengambil alih posisi vertikal elemen navigasi ketika diperbaiki, Anda mungkin juga menjatuhkan bagian deklarasi top: 15px
dari CSS Anda. Jika Anda adalah bagian dari proyek besar, dengan orang-orang yang terpisah mengerjakan desain dan skrip front-end, ini mungkin merupakan masalah karena mudah kehilangan jejak peretasan tersebut. Untuk memberi tahu Anda, ada plugin - seperti jQuery yang sangat baik dari Ariel Flesler. jQuery.Rule yang dapat digunakan untuk menjembatani kesenjangan antara skrip dan stylesheet. Anda harus memutuskan sendiri apakah Anda membutuhkan sesuatu seperti itu.
Anda pasti bisa mencapai efek yang sama dengan CSS @keyframes
, tetapi ada jauh lebih sedikit dukungan untuk mereka (dan banyak awalan vendor), mereka kurang fleksibel, dan animasi 'atas' akan menjadi besar tidak boleh tidak. Karena kami tidak meninggalkan jejak peningkatan progresif, tidak ada alasan untuk tidak tetap menggunakan fungsionalitas jQuery yang kuat.
Langkah 6: Highlighting dan Smooth Scrolling
Anda mungkin perlu mengubah item mana yang disorot saat pembaca maju melewati bagian halaman yang berbeda. Dengan Waypoints, hal ini cukup mudah untuk dicapai. Anda akan perlu untuk menambah skrip berikut:
1 |
$(function() { |
2 |
… |
3 |
// copy from here… |
4 |
|
5 |
var sections = $('section'); |
6 |
var navigation_links = $('nav a'); |
7 |
|
8 |
sections.waypoint({ |
9 |
handler: function(event, direction) { |
10 |
// handler code |
11 |
}, |
12 |
offset: '35%' |
13 |
}); |
14 |
|
15 |
// …to here |
16 |
}); |
Saat ini kami menggunakan sebuah offset yang dinyatakan sebagai persentase dari ketinggian window. Secara efektif, ini berarti bahwa garis imajiner yang memberitahu skrip kami bagian apa yang saat ini sedang dilihat ditempatkan sekitar sepertiga dari atas viewport - benar tentang di mana pemirsa akan melihat ketika membaca teks yang panjang. Solusi yang lebih kuat dapat menggunakan fungsi untuk beradaptasi dengan perubahan ketinggian bilah navigasi.
Kode yang akan kita gunakan dalam fungsi handler kita sedikit kurang jelas. Ini dia:
1 |
var active_section; |
2 |
active_section = $(this); |
3 |
if (direction === "up") active_section = active_section.prev(); |
4 |
|
5 |
var active_link = $('nav a[href="#' + active_section.attr("id") + '"]'); |
6 |
navigation_links.removeClass("selected"); |
7 |
active_link.addClass("selected"); |
Pertama, kita perlu tahu bagian mana yang saat ini sedang dilihat. Jika kami menggulir ke bawah, maka bagian yang dimiliki oleh waypoint itu adalah yang sama yang menjadi aktif. Menggulir ke atas melewati waypoint, bagaimanapun, berarti bahwa itu adalah bagian sebelumnya yang ditampilkan - jadi kami menggunakan .prev()
untuk memilihnya. Kemudian, kami menghapus kelas yang dipilih
dari semua tautan di navbar, sebelum menerapkannya kembali ke kelas yang atribut href
sesuai dengan id
bagian yang sedang aktif.
Ini bekerja dengan sangat baik; jika Anda ingin melampaui menambah dan menghapus kelas, Anda mungkin ingin melihat ke dalam plugin seperti LavaLamp.
Pada titik tertentu, Anda mungkin telah memperhatikan bahwa mengklik tautan di navbar menempatkan bagian atas bagian paling atas dari viewport browser. Ini cukup intuitif ketika tidak ada yang mengaburkan bagian layar itu; sekarang kami memiliki navbar di sana, itu menjadi gangguan besar. Di sinilah ScrollTo Ariel Flesler datang untuk menyelamatkan. Sertakan di halaman Anda, dan kemudian tambahkan kode berikut:
1 |
navigation_links.click( function(event) { |
2 |
|
3 |
$.scrollTo( |
4 |
$(this).attr("href"), |
5 |
{ |
6 |
duration: 200, |
7 |
offset: { 'left':0, 'top':-0.15*$(window).height() } |
8 |
} |
9 |
); |
10 |
|
11 |
}); |
(tentu saja, kode itu berjalan di sebelum penutup kurung kurawal!)
Meskipun ada cara yang lebih baik untuk mengikat fungsi untuk mengklik event, kami akan tetap dengan yang paling sederhana: .click()
. Metode .scrollTo()
dipanggil dengan cara yang sangat mirip dengan .waypoint()
. Dibutuhkan dua parameter - target gulir dan objek yang berisi opsi yang berbeda, yang, dalam hal ini, cukup jelas. Atribut href
tautan yang diklik berfungsi dengan baik sebagai target gulir, dan ekspresi yang digunakan sebagai offset atas menempatkan target pada 15% dari tinggi viewport.
Kesimpulan
Dan tampaknya kita sudah selesai. Saya telah memperkenalkan Anda dengan plugin kecil yang praktis yaitu Waypoints, dan kami telah membahas beberapa kasus penggunaan yang akan memberi Anda gambaran tentang berbagai hal yang dapat Anda capai dengan itu. Kami juga menerapkan perilaku pengguliran yang jauh lebih intuitif untuk digunakan dengan navigasi kami. Lemparkan beberapa Ajax ke dalam mix, dan Anda sedang menuju cara membangun jenis pengalaman Web yang mendalam dan imersif yang akan menjadi masa depan Web ... yah, lebih besar kemungkinannya akan menjadi trend untuk sementara waktu dan kemudian menjadi biasa, membuat veteran Web nostalgia tentang hal-hal yang dulu. Tapi hei, begitulah yang terjadi.
Adapun pita, kelemahan terbesar mereka adalah ini: mereka hanya ilusi. Sisi pita tidak benar-benar mengitari tepi wadah; mereka hanya muncul seperti itu, yang menjadi cukup jelas ketika pita melewati elemen yang menonjol dari tepi halaman.



Karena cara kerja z-index, tampaknya tidak ada cara sederhana untuk menyelesaikan konflik ini, kecuali untuk menghindarinya. Namun, dengan beberapa imajinasi, serta pengetahuan dasar tentang jQuery, Anda dapat merekayasa cara agar elemen-elemen ini keluar dari jalan pita saat mendekati mereka. Melakukan ini jauh di luar cakupan tutorial ini, meskipun; semoga, saya bisa menunjukkannya kepada Anda cepat atau lambat dalam bentuk kiat cepat, baik di sini atau di Nettuts. Tetap disini!