Masalah dan Kasus Penggunaan
Navigasi dokumen penuh menggantikan dokumen beserta judulnya. Navigasi halus (soft navigation) pada SPA mempertahankan dokumen yang sama, sehingga fokus dapat tertinggal pada tautan yang konten di sekitarnya telah menghilang. Pengguna pembaca layar mungkin tidak mendengar indikasi berguna apa pun bahwa produk baru, langkah checkout, atau halaman kesalahan telah siap.
Kebijakan ini harus mencakup lima transisi yang berbeda: pemuatan awal, perubahan rute yang diinisiasi pengguna, filter atau pengurutan di tempat, navigasi yang digantikan atau dibatalkan, dan Back/Forward peramban. Kebijakan ini juga harus berdampingan dengan perilaku milik komponen seperti dialog. Tujuannya adalah konteks yang dapat diprediksi, bukan memindahkan fokus setelah setiap mutasi URL.
Apa yang Dievaluasi oleh Pewawancara
Pewawancara mencari model keputusan semantik. "Fokuskan heading pada setiap perubahan rute" terdengar aksesibel tetapi merusak filter, perubahan hash, hidrasi awal, dan pemulihan riwayat. Jawaban yang kuat pertama-tama menentukan apakah tugas pengguna telah berubah.
Mereka juga mengharapkan pengetahuan tentang peramban: sebuah heading dapat menerima fokus terprogram dengan tabIndex={-1} tanpa masuk ke dalam urutan Tab sekuensial; focus() biasanya menggulirkan elemen; preventScroll memisahkan pemulihan fokus dari pemulihan gulir (scroll); dan nilai tabindex positif menciptakan urutan fokus yang rapuh.
Terakhir, jawaban harus menangani konkurensi. Jika rute B selesai setelah rute C, B tidak boleh memperbarui judul atau merebut fokus. Pemeriksaan otomatis dapat membuktikan elemen aktif, judul, dan urutan, tetapi tidak dapat membuktikan apa yang diumumkan oleh setiap pasangan peramban dan teknologi asistif.
Pertanyaan Klarifikasi Sebelum Menjawab
- Transisi mana yang memulai tugas baru? Perpindahan dari produk ke checkout memulainya; mengubah urutan penyortiran biasanya tidak. Hal ini menentukan apakah fokus berpindah atau tetap pada kontrol penginisiasi.
- Kapan sebuah rute di-commit? Fokus hanya boleh dijalankan ketika rute yang menang telah me-render heading utama finalnya, bukan saat klik, mutasi URL, atau tampilan skeleton.
- Apa yang mengontrol overlay? Sebuah dialog mempertahankan fokus awal, jebakan fokus (focus trap), dan kontrak pengembalian fokusnya sendiri. Kebijakan rute tidak boleh bersaing dengannya.
- Apa yang dipulihkan oleh riwayat? Tentukan apakah produk memerlukan pemulihan fokus, scroll, atau keduanya per entri riwayat. Keduanya memerlukan koordinasi untuk menghindari lompatan ganda.
- Peramban dan teknologi asistif mana yang didukung? Perilaku pengumuman bervariasi, sehingga matriks rilis harus eksplisit.
- Bisakah setiap rute menyediakan judul deskriptif dan satu heading utama? Jadikan hal ini sebagai bagian dari kontrak rute; gunakan landmark utama hanya sebagai fallback terkontrol.
Kerangka Jawaban 30 Detik
"Saya mengklasifikasikan navigasi sebelum memindahkan fokus. Pemuatan awal tidak melakukan apa pun. Perubahan tugas yang diinisiasi pengguna dan telah di-commit memperbarui judul dokumen dan memfokuskan H1 deskriptif baru, yang dibuat dapat difokuskan secara terprogram dengan tabIndex=-1. Filter pada tugas yang sama mempertahankan kontrol dan melaporkan hasil yang selesai melalui polite status region yang persisten. Setiap navigasi memiliki token, sehingga hanya rute commit terbaru yang dapat menerapkan judul dan fokus. Pada Back/Forward, saya memulihkan target semantik valid yang disimpan untuk entri riwayat tersebut, jika tidak ada saya menggunakan H1, mengoordinasikan fokus dengan pemulihan scroll. Saya menguji pemuatan awal, navigasi cepat, kesalahan, filter, riwayat, urutan keyboard, fokus yang terlihat, dan pembaca layar nyata."
Pembahasan Mendalam Langkah demi Langkah
Mulailah dengan tabel transisi:
| Transisi | Aksi fokus | Pengumuman |
|---|---|---|
| Pemuatan awal atau hidrasi | Jangan paksa fokus | Perilaku dokumen/judul bawaan |
| PUSH ke tugas baru | Fokuskan H1 rute yang di-commit | Judul yang diperbarui ditambah heading yang difokuskan |
| Filter, pengurutan, atau paginasi pada tugas yang sama | Pertahankan kontrol penginisiasi | Pembaruan hasil/status polite jika berguna |
| POP dari Back/Forward | Pulihkan target valid yang disimpan; jika tidak, H1 | Konteks yang dipulihkan atau heading yang difokuskan |
| Pengalihan atau rute kesalahan | Fokuskan H1 yang di-commit dari rute tersebut | Judul dan heading finalnya |
| Buka/tutup dialog | Serahkan ke kontrak dialog | Label dialog dan target pengembalian |
Kontrak rute menyediakan judul final, referensi H1 deskriptif, dan kunci rute semantik. Berikan H1 atribut tabIndex={-1}. Elemen ini tetap berada di luar urutan Tab normal, tetapi kode dapat memfokuskannya. Pertahankan indikator fokus yang terlihat. Skip link tetap menjadi kontrol pertama yang dapat difokuskan keyboard dan menargetkan main; ini menyelesaikan bypass navigasi berulang dan tetap bernilai ketika fokus rute dikelola.
Fokus berada pada batasan commit (commit boundary). Tetapkan token yang meningkat secara monoton untuk setiap upaya navigasi. Ketika data dan UI untuk suatu rute selesai, terapkan efek hanya jika tokennya masih yang terkini dan H1 telah terpasang. Jangan gunakan timeout tetap: kecepatan jaringan dan proses rendering membuatnya tidak dapat diandalkan.
beginNavigation(kind):
token = nextToken()
rememberCurrentFocus(historyEntryKey)
commitRoute(token, kind, title, heading):
if token != currentToken or heading is not connected:
return
document.title = title
if kind is PUSH or semantic-task REPLACE:
heading.focus()
else if kind is POP:
focus(validSavedTarget(historyEntryKey) or heading)Simpan ID fokus lokal rute yang stabil daripada jalur CSS yang dihasilkan. Pada POP, pulihkan hanya jika elemen masih ada, terlihat, aktif, dan bermakna dalam status yang dipulihkan. Jika tidak, gunakan H1. Jika router memulihkan scroll secara independen, gunakan focus({ preventScroll: true }) lalu pulihkan scroll sekali; untuk PUSH normal, membiarkan fokus menampilkan H1 biasanya lebih jelas.
Hindari pengulangan ucapan. Memfokuskan H1 baru setelah memperbarui judul sering kali memberikan konteks yang cukup, meskipun ucapan persisnya bervariasi menurut teknologi asistif. Jangan mengumumkan judul yang sama di live region secara default. Untuk filter yang mempertahankan fokus, region role="status" atau aria-live="polite" yang persisten dapat mengumumkan jumlah hasil yang selesai. Cadangkan pengumuman asertif hanya untuk informasi yang benar-benar mendesak karena dapat memotong ucapan yang sedang berlangsung.
Tolok ukur pengujian mengikuti kebijakan. Pada hidrasi awal, aplikasi tidak boleh merebut fokus. Pada PUSH, setelah commit final, document.activeElement adalah H1 baru, judul bersifat final, dan Tab berikutnya mencapai elemen interaktif logis pertama. Pada perubahan filter, pemicu mempertahankan fokus dan teks status diperbarui sekali. Dalam persaingan A→B→C di mana B selesai terakhir, C mempertahankan judul dan fokus. Rute kesalahan dan pengalihan memfokuskan heading mereka sendiri. POP memulihkan target valid yang disimpan atau beralih ke fallback secara deterministik.
Jalankan pemeriksaan DOM otomatis untuk semua kasus tersebut, termasuk pelepasan (unmount) target dan tata letak reduced-motion/zoom. Kemudian telusuri secara manual dengan keyboard dan kombinasi yang didukung seperti VoiceOver/Safari dan NVDA atau JAWS dengan peramban yang didukung. Verifikasi fokus yang terlihat, urutan logis, tidak ada scroll yang tidak terduga, dan pengumuman yang dapat dipahami. Catat versi peramban dan teknologi asistif karena output ucapan adalah hasil integrasi, bukan jaminan DOM.
Contoh Jawaban Berkualitas Tinggi
"Saya akan menjadikan perilaku fokus sebagai bagian dari kontrak semantik router. Setiap rute mengekspos judul dokumen final dan referensi H1 deskriptif. Saya mengklasifikasikan transisi: hidrasi awal tidak memindahkan fokus; PUSH yang diinisiasi pengguna yang mengubah tugas memfokuskan H1 final setelah commit; filter atau penyortiran mempertahankan kontrol penginisiasi; dan POP mencoba memulihkan target tersimpan yang stabil sebelum beralih ke H1.
H1 memiliki tabIndex=-1, sehingga dapat difokuskan secara terprogram tanpa menambahkan perhentian Tab ekstra. Saya mempertahankan gaya fokus yang terlihat dan mempertahankan skip link yang menargetkan main. Judul dan fokus berubah bersamaan hanya setelah rute yang menang di-commit. Setiap navigasi menerima token, dan penyelesaian asinkron yang lebih lama akan diabaikan, yang mencegah rute yang dibatalkan merebut fokus.
Untuk riwayat, saya menyimpan ID fokus semantik lokal rute per entri riwayat. Saya hanya memulihkan target yang terhubung, terlihat, dan aktif. Jika pemulihan scroll terpisah, saya memfokuskan dengan preventScroll dan memulihkan scroll sekali. Pembaruan asinkron pada tugas yang sama menggunakan polite status region yang persisten; saya menghindari pengulangan judul rute di heading sekaligus di live region.
Saya akan mengotomatiskan pengujian untuk elemen aktif, judul, urutan Tab, retensi fokus filter, navigasi cepat A→B→C, pengalihan, kesalahan, dan fallback POP. Kemudian saya akan menguji ucapan nyata, fokus yang terlihat, dan scrolling dengan matriks keyboard dan pembaca layar yang didukung. Itu memisahkan perilaku DOM yang deterministik dari perilaku teknologi asistif yang harus kita amati."
Kesalahan Umum
- Fokus pada setiap perubahan URL → filter dan perubahan hash mengganggu tugas → klasifikasikan transisi semantik terlebih dahulu.
- Fokus saat tautan diklik → tujuan mungkin belum ada atau mungkin dibatalkan → fokuskan hanya pada rute commit yang menang.
- Menggunakan timeout → render lambat dan cepat bersaing secara berbeda → gunakan siklus hidup rute dan token navigasi.
- Fokus pada
bodyatau menambahkantabindexpositif → konteks dan urutan menjadi tidak jelas → gunakan H1 deskriptif dengantabIndex=-1. - Selalu melompat ke H1 pada POP → tombol Back menghilangkan posisi pengguna → pulihkan target riwayat yang valid dengan fallback deterministik.
- Mengumumkan judul dua kali → pengguna mendengar ucapan yang redundan → pilih konteks heading yang difokuskan terlebih dahulu dan gunakan live status untuk pembaruan di tempat.
- Menganggap pemindaian aksesibilitas otomatis sebagai bukti mutlak → alat tersebut tidak dapat memvalidasi output lisan yang sebenarnya → tambahkan pengujian manual dengan keyboard dan teknologi asistif.
Pertanyaan Lanjutan dan Tanggapan
Pertanyaan Lanjutan 1: Mengapa tidak selalu memfokuskan landmark main?
H1 biasanya memberikan nama yang lebih spesifik untuk tugas baru. main adalah fallback yang masuk akal ketika kontrak rute tidak dapat menyediakan heading, tetapi mewajibkan setiap rute menyediakannya akan meningkatkan struktur visual, outline dokumen, dan kemampuan pengujian.
Pertanyaan Lanjutan 2: Haruskah navigasi menggunakan mouse juga memindahkan fokus?
Jika tindakan yang diinisiasi pengguna menggantikan tugas utama, konteks yang konsisten akan berguna terlepas dari perangkat inputnya, termasuk bagi pengguna pembaca layar yang menggunakan klik. Dasarkan keputusan pada navigasi semantik, bukan pada tebakan tentang penggunaan keyboard. Hindari memindahkan fokus untuk pembaruan di latar belakang.
Pertanyaan Lanjutan 3: Bagaimana jika B selesai setelah C pada navigasi cepat?
Token B tidak lagi cocok dengan navigasi saat ini, sehingga efek commit-nya kembali tanpa mengubah judul, fokus, atau status. Membatalkan permintaan B menghemat pemrosesan, tetapi pemeriksaan token tetap diperlukan karena pembatalan mungkin terlambat atau tidak didukung.
Pertanyaan Lanjutan 4: Bagaimana fokus dan pemulihan scroll berinteraksi?
focus() normal dapat menggulirkan target ke dalam tampilan. Pada POP, jika router memulihkan posisi scroll tersimpan secara terpisah, gunakan preventScroll, validasi dan fokuskan elemen yang disimpan, lalu lakukan satu kali pemulihan scroll. Tentukan satu pemilik agar kode fokus dan router tidak saling bertabrakan.
Pertanyaan Lanjutan 5: Kapan live region harus bersifat assertive?
Hanya ketika keterlambatan mendengar menimbulkan masalah serius, seperti pesan sesi atau keselamatan yang mendesak. Jumlah hasil biasa dan pembaruan penyelesaian harus bersifat polite. Konteks rute biasanya berasal dari judul final dan heading yang difokuskan, menghindari pengumuman kedua.
Pertanyaan Lanjutan 6: Apakah ini dengan sendirinya menjamin kepatuhan WCAG?
Tidak. Ini mendukung urutan fokus dan konteks yang dapat dipahami dalam aplikasi dinamis, tetapi kepatuhan juga bergantung pada semantik, nama, pengoperasian keyboard, kontras, penanganan kesalahan, dan kriteria lainnya. Uji seluruh alur perjalanan pengguna terhadap target kesesuaian produk.