Vue · Bab 9
UI/UX Responsif dan Aksesibilitas
Menata aplikasi Vue mobile-first dengan media query min-width, menu lipat ber-aria-expanded, target sentuh 44px, pengumuman aria-live dan role alert, teks keadaan kosong dan galat yang membantu, konfirmasi hapus dua tahap, serta kontras warna.
Aplikasi frontend terpisah di tingkat 5 dibuka dari ponsel sama seringnya dengan dari laptop, dan dipakai juga oleh orang yang mengandalkan pembaca layar atau keyboard. Bab ini tidak menambah fitur Vue baru. Yang dipelajari adalah cara memakai Vue yang sudah kamu kuasai supaya aplikasinya nyaman untuk semua orang: tata letak responsif, status yang diumumkan, dan teks yang membantu. Contohnya katalog Perpustakaan Pelita.
9.1 Mobile-first
Mobile-first berarti gaya dasar ditulis untuk layar sempit, lalu @media (min-width: …) menambah kolom saat layar cukup lebar. Kebalikannya (desktop-first dengan max-width) cenderung menumpuk aturan yang saling membatalkan.
🧪 Coba ubah: pakai tombol lebar di atas preview. Di Ponsel 375 kartu bertumpuk satu kolom; di Desktop 1024 menjadi tiga kolom. Uji kedua lebar ini setiap kali mengubah tata letak.
Belum ada output.
9.2 Navigasi Lipat
Di layar sempit, menu disembunyikan di balik tombol “Menu”. Tombol itu memberi tahu pembaca layar dua hal: menu mana yang dikendalikannya (aria-controls) dan apakah menu sedang terbuka (aria-expanded, berupa teks "true" atau "false").
🧪 Coba ubah: di lebar 375, buka menu lalu periksa atribut tombol di DevTools. Nilai aria-expanded ikut berubah karena terikat ke state yang sama dengan kelas buka.
Belum ada output.
9.3 Target Sentuh dan Fokus
- Tombol dan tautan yang disentuh jari minimal 44px tinggi dan lebarnya (
min-height: 44px). - Jangan menghapus garis fokus (
outline: none) tanpa pengganti. Pengguna keyboard melihat posisinya lewat:focus-visible. - Setelah pindah rute, fokus dipindah ke judul halaman (bab 6), supaya pembaca layar mengumumkan halaman baru.
9.4 Mengumumkan Perubahan
Perubahan yang terjadi tanpa pindah halaman, misalnya buku masuk ke daftar pinjam, tidak terlihat oleh pembaca layar. Elemen aria-live="polite" mengumumkan isinya setiap kali berubah. Untuk galat yang harus segera diketahui, pakai role="alert".
🧪 Coba ubah: hapus teks “(sedang dipinjam)”. Tombol nonaktif saja tidak menjelaskan kenapa buku tidak bisa dipinjam.
Belum ada output.
Elemen aria-live sebaiknya sudah ada di halaman sejak awal (boleh kosong). Elemen yang baru dibuat bersamaan dengan teksnya sering tidak diumumkan.
9.5 Teks Keadaan yang Membantu
Setiap halaman yang mengambil data punya empat keadaan (bab 4): memuat, kosong, galat, berhasil. Teks untuk keadaan kosong dan galat menentukan apakah pengguna tahu langkah berikutnya:
| Keadaan | Kurang membantu | Membantu |
|---|---|---|
| kosong | “Tidak ada data.” | “Belum ada buku di daftar pinjam. Cari judul di katalog.” |
| galat jaringan | “Error 0” | “Katalog gagal dimuat. Periksa koneksi lalu coba lagi.” |
| galat validasi | “422 Unprocessable” | pesan per kolom di sebelah isiannya (bab 5) |
Jangan menampilkan kode status mentah atau pesan teknis dari server kepada pengguna. Kode itu berguna di konsol untuk pengembang, bukan di layar.
9.6 Konfirmasi Hapus Dua Tahap
Aksi yang merusak, seperti menghapus data anggota, perlu konfirmasi. confirm() bawaan browser memblokir halaman, tidak bisa ditata, dan di dalam sandbox preview selalu mengembalikan false. Pola yang lebih baik: tombol “Hapus” diganti tombol “Ya, hapus” dan “Batal” di baris itu saja.
🧪 Coba ubah: klik “Hapus” di baris Rina lalu di baris Bayu. Hanya satu baris yang menunggu konfirmasi pada satu waktu, karena yakin menyimpan satu nomor.
Belum ada output.
aria-label “Hapus anggota Rina” membedakan tombol-tombol yang tulisannya sama. Tanpa itu, pembaca layar membacakan “Hapus, Hapus, Hapus”.
9.7 Kontras dan Warna
- Teks biasa butuh kontras minimal 4,5:1 terhadap latar (WCAG AA). Abu-abu muda di atas putih biasanya gagal.
- Jangan memakai warna saja untuk menyampaikan status. Buku yang sedang dipinjam ditandai dengan teks “(sedang dipinjam)”, bukan hanya warna merah.
- Periksa dengan alat seperti axe atau Lighthouse di DevTools, lalu dengarkan sendiri dengan pembaca layar sistem operasi.
9.8 Fitur yang Sama untuk Ketiga Kalinya
Di tingkat 3 kamu membuat katalog dengan Blade, di tingkat 4 sebagai API, dan sekarang sebagai klien Vue. Fiturnya sama, tetapi biayanya berpindah:
| Urusan | Blade (server) | API + Vue (klien) |
|---|---|---|
| state halaman | dibuat ulang setiap request | disimpan di komponen dan store |
| galat | halaman galat dari server | ditangani per request: memuat, kosong, galat, 401, 403, 422 |
| login | sesi cookie | token di header, guard, keluar otomatis saat 401 |
| aksesibilitas | HTML statis sudah cukup banyak | fokus, pengumuman, dan atribut ARIA harus dijaga sendiri |
| responsif | CSS | CSS, ditambah komponen yang berubah (menu lipat) |
Frontend terpisah memberi pengalaman yang lebih cepat dan luwes, dengan harga: lebih banyak keadaan yang harus kamu pikirkan.
Rangkuman
- Mobile-first: gaya dasar untuk layar sempit,
@media (min-width: …)menambah kolom; uji di 375 dan 1024. - Menu lipat memakai
aria-controlsdanaria-expandedyang terikat ke state. - Target sentuh 44px, fokus terlihat,
aria-liveuntuk kabar,role="alert"untuk galat. - Teks keadaan memberi tahu langkah berikutnya; konfirmasi hapus di halaman, bukan
confirm().
Berikutnya: Capstone bab 9 menggabungkan semuanya di aplikasi Smart Retail: etalase responsif, keranjang Pinia, transaksi kasir, dan hapus khusus admin.