JavaScript telah mengubah dokumen statik menjadi perisian. Aplikasi satu halaman (SPA) terasa pantas. Tiada muat semula halaman penuh, tiada skrin putih yang berkelip. Namun, kepantasan itu datang dengan kos yang sering diabaikan oleh banyak pasukan: mekanisme asas web mula merosot. Navigasi menjadi rapuh. Enjin carian sukar mengikuti laluan. Pembaca skrin menjadi keliru. Dan pengguna mendapati diri mereka terperangkap dalam antara muka yang kelihatan seperti laman web tetapi berkelakuan seperti aplikasi desktop yang rosak.

Punca utamanya biasanya adalah div dengan pengendali onClick.

Berhenti Menggunakan Div sebagai Pautan

Sebuah div tidak membawa sebarang makna semantik. Ia hanyalah sebuah kotak. Apabila anda memasang pengendali klik padanya dan menggunakannya untuk menghalakan pengguna ke paparan baharu, anda meminta pelayar melayan sebuah kotak kadbod seperti sebuah pintu. Pelayar akan menolaknya. Begitu juga dengan setiap alatan yang dibina di sekeliling pelayar.

Pembaca skrin tidak mengumumkan div sebagai pautan atau butang. Ia akan melangkauinya, atau membacanya sebagai teks biasa. Pengguna yang menavigasi menggunakan suara tidak dapat mensasarkannya. Pengangkut (crawler) enjin carian, yang mengimbas halaman anda untuk mencari URL, tidak akan melihat apa-apa untuk diikuti. Laluan anda seolah-olah tidak wujud.

Lebih buruk lagi, anda kehilangan tingkah laku yang sudah diketahui oleh pengguna. Pautan sebenar membolehkan seseorang klik kanan untuk membukanya dalam tab baharu, menandakan (bookmark) destinasi, atau menyalin alamat untuk dikongsi. Pengguna papan kekunci menjangkakan untuk menekan Tab untuk mencapainya dan Enter untuk membukanya. Sebuah div tidak menawarkan semua ini. Walaupun anda menambah tabIndex, role="link", dan pendengar papan kekunci, anda sebenarnya sedang membina semula—secara tidak sempurna—apa yang pelayar berikan secara percuma. Dan anda pasti akan terlepas pandang kes tertentu (edge case). Anda memang selalu begitu.

Gunakan Anchor untuk Destinasi, Button untuk Tindakan

HTML sudah pun menyelesaikan masalah ini. Kekeliruan bermula kerana kedua-dua elemen kelihatan boleh diklik, jadi pembangun menganggapnya boleh bertukar ganti. Hakikatnya tidak.

Gunakan tag <a apabila anda ingin mengalihkan pengguna ke URL baharu. Bukan pertukaran paparan simulasi, bukan perubahan keadaan (state), tetapi lokasi yang sebenar. Atribut href harus mengandungi alamat yang nyata:

<a href="/docs">Documentation</a>

Itu sahaja. Jika pengguna ingin pergi ke suatu tempat, gunakan pautan.

Gunakan <button> apabila sesuatu berlaku pada halaman semasa. Butang adalah untuk tindakan seperti:

  • Membuka modal
  • Menghantar borang
  • Menyimpan tetapan
  • Menukar (toggle) menu

Pautan adalah untuk destinasi. Butang adalah untuk tindakan. Mencampuradukkan kedua-duanya akan mengelirukan antara muka anda dan merosakkan jangkaan pengguna.

Biarkan Pelayar Melakukan Tugasnya

Pelayar moden adalah hasil evolusi dan penstandardan selama berdekad-dekad. Ia mengendalikan keselamatan, sejarah, pra-muat (prefetching), dan kebolehcapaian dengan lebih baik daripada mana-mana JavaScript yang anda tulis sendiri.

Tag anchor yang tulen secara automatik mengisi timbunan sejarah (history stack) pelayar. Ia berfungsi dengan menu konteks asli. Ia menyertai algoritma pra-muat terbina dalam pelayar apabila pengguna menghalakan tetikus (hover) atau memfokuskan padanya, menjadikan aplikasi anda terasa lebih pantas tanpa anda perlu menulis sebaris kod pun. Ia menghormati pilihan pengguna untuk membuka pautan. Ia bekerjasama dengan pengurus kata laluan, alat terjemahan, dan mod pembaca.

Apabila anda menggantikannya dengan fungsi navigasi JavaScript, anda mengetepikan semua kelebihan tersebut. Anda bukan sekadar kehilangan ciri-ciri; anda memaksa pengguna untuk meninggalkan tabiat yang telah mereka bina di setiap laman web lain di internet. Itu bukan keputusan teknikal. Itu adalah pengalaman pengguna yang tidak mesra.

Semak Apa yang Sebenarnya Dirender oleh Framework Anda

React Router, Vue Router, komponen Link Next.js, SvelteKit. Alatan ini menjadikan penghalaan sisi klien (client-side routing) terasa mudah. Namun, abstraksi membawa kepada kesilapan.

Periksa DOM anda. Buka alatan pembangun (developer tools) pelayar dan lihat elemen yang dikeluarkan oleh framework anda. Komponen <Link> sepatutnya dirender sebagai tag <a yang sebenar dengan atribut href yang sah dalam HTML akhir. Jika ia dirender sebagai span, div, atau apa-apa sahaja tanpa href yang betul, abstraksi anda telah mengecewakan anda. Baiki komponen tersebut. Atasi (override) tetapan lalai. Gunakan prop passHref atau setaraf dengannya dalam framework tersebut. Jangan percaya bahawa framework akan melakukannya dengan betul tanpa pengesahan.

Ini juga penting untuk ketidakpadanan penghidratan (hydration mismatches). Jika pelayan (server) merender pautan dan klien menghidratkannya (hydrates) menjadi bukan pautan, anda mencipta pepijat kebolehcapaian yang sukar dikesan kerana HTML kelihatan betul dalam kod sumber anda tetapi salah dalam DOM yang sedang berjalan.

Larang Destinasi Palsu

Terdapat satu corak yang enggan mati: href="javascript:void(0)". Pembangun menggunakannya apabila mereka mahukan sesuatu yang kelihatan seperti pautan tetapi bertindak seperti butang, biasanya kerana mereka tidak mahu menggayakan (style) butang atau kerana kod sedia ada (codebase) yang lama menuntutnya.

Berhenti. Ini bukan URL. Ia tidak memberikan destinasi kepada pelayar. Ia mencemarkan timbunan sejarah (history stack) dengan keadaan yang tidak boleh digunakan. Ia merosakkan sejarah pelayar dan kebolehcapaian. Ia adalah satu perangkap. Jika anda memerlukan tingkah laku klik tanpa navigasi, anda memerlukan <button>. Gayakannya mengikut rupa yang anda mahukan. CSS tidak peduli sama ada elemen tersebut adalah butang atau pautan. Pengguna anda peduli.

Tulis Teks yang Menjelaskan Ke Mana Pengguna Akan Pergi

Perkataan di dalam pautan anda adalah penting. Pengguna pembaca skrin (screen reader) sering memaparkan senarai setiap pautan pada halaman untuk imbasan pantas. Jika semua pautan anda menyebut "Baca lebih lanjut" atau "Klik di sini," senarai tersebut akan menjadi gangguan yang tidak berguna.

Jadilah spesifik. Bandingkan ini:

  • Buruk: <a href="/security/api-guide">Baca lebih lanjut</a>
  • Baik: <a href="/security/api-guide">Baca panduan keselamatan API</a>

Pilihan kedua memberitahu pengguna dengan tepat apa yang akan mereka temui. Ia memberikan konteks kepada enjin carian tentang halaman destinasi tersebut. Ia menjadikan senarai pautan anda mudah dilayari. Teks pautan yang deskriptif adalah salah satu cara termurah untuk meningkatkan kebolehcapaian yang boleh anda capai.

Uji dengan Bersungguh-sungguh

Seni bina tidak bermakna jika anda tidak mengesahkannya.

Pertama, uji aliran papan kekunci anda. Cabut tetikus anda. Gunakan Tab untuk melalui setiap elemen interaktif pada laman anda. Setiap pautan tulen mesti menunjukkan garis luar fokus (focus outline) yang jelas, bukan sekadar cahaya malap yang hilang pada latar belakang anda, tetapi satu bulatan jelas yang boleh dikesan oleh mata yang letih. Tekan Enter. Ia mesti mengaktifkan pautan tersebut. Jika Tab melangkau elemen, atau jika Enter tidak melakukan apa-apa, anda mempunyai pepijat (bug).

Kedua, uji laluan (routes) anda pada peringkat pelayan. Penghalaan sisi klien (client-side routing) hanyalah lapisan nipis. Jika pengguna menandakan /dashboard/reports sebagai penanda buku dan kembali esok, atau menekan butang segar semula (refresh), pelayan anda mesti tahu cara untuk menyediakan halaman tersebut. Konfigurasikan proksi terbalik (reverse proxy) atau rangka kerja pelayan anda untuk kembali ke kerangka aplikasi (application shell) anda bagi laluan yang tidak diketahui, atau sediakan HTML yang betul secara terus. Ralat 404 semasa segar semula bukanlah pepijat kecil. Ia adalah janji yang dimungkiri.

JavaScript ialah lapisan yang berkuasa