Pengguna keyboard menelusuri halaman dengan tombol Tab, dan satu-satunya petunjuk bagi mereka tentang posisi saat ini adalah indikator fokus yang berpindah dari satu elemen ke elemen berikutnya. Masalahnya, pseudo-class :focus tidak membedakan asal fokus: klik mouse dan tekanan Tab menyalakan aturan yang sama, sehingga cincin tebal tampil juga bagi pengguna mouse yang tidak membutuhkannya. Pseudo-class :focus-visible memecah persoalan tersebut — browser menilai sendiri kapan indikator benar-benar perlu tampil. Pada Chapter ini kita membedakan keduanya, merancang indikator yang tetap ada, lalu melatih cara mengujinya dengan keyboard.

Perbedaan :focus dan :focus-visible #

:focus cocok dengan elemen yang sedang difokuskan, apa pun penyebabnya: klik, Tab, atau pemanggilan focus() dari skrip. :focus-visible menyerahkan keputusan kepada browser: aturan hanya berlaku bila browser menilai indikator fokus memang harus terlihat. Tabel berikut merangkum perilaku umumnya:

Cara memfokuskan:focus:focus-visible
Klik mouse pada tombolcocokumumnya tidak
Tekan Tab ke elemencocokcocok
Klik atau Tab ke input tekscocokcocok
Fokus dipindahkan lewat skripcocokdinilai browser

Heuristiknya ringkas: pada elemen isian teks, kursor teks memang harus terlihat sehingga fokus selalu dianggap visible. Pada tombol dan tautan, klik mouse dianggap sinyal bahwa pengguna memakai pointer dan tidak memerlukan cincin; tekanan Tab sebaliknya adalah sinyal keyboard yang wajib ditanggapi dengan indikator.

Merancang Indikator Fokus #

Indikator paling aman dibangun dari outline karena digambar di luar kotak tanpa menggeser elemen di sekitarnya — berbeda dengan border yang mengubah layout (perbedaan lengkapnya dibahas pada Chapter Outlines ):

css
.tombol {
  background-color: rgb(37, 99, 235);
  color: rgb(255, 255, 255);
  border: none;
  border-radius: 8px;
  padding: 10px 18px;
  font: inherit;
}

.tombol:focus-visible {
  outline: 3px solid rgb(37, 99, 235);
  outline-offset: 2px;
}
  1. Baris 1–7 (.tombol): gaya dasar tombol tanpa outline apa pun, sehingga gaya fokus sepenuhnya ditentukan aturan berikutnya.
  2. Baris 9–12 (:focus-visible): cincin biru 3px solid dengan outline-offset: 2px — celah 2px antara tepi tombol dan cincin membuat keduanya tidak menyatu.
  3. Pembagian pengalaman: pengguna mouse mengeklik tombol tanpa melihat cincin; pengguna keyboard mendapat cincin penuh. Satu aturan, dua pengalaman yang tepat sasaran.

Hasil di Browser:

text
Tombol dalam keadaan diam tampil dengan latar rgb(37, 99, 235), teks putih,
dan sudut 8px — tanpa cincin fokus.
Kotak pembanding pada demo menampilkan outline statis 3px solid rgb(37, 99, 235)
dengan offset 2px, nilai identik dengan aturan :focus-visible pada tombol.
Input teks berborder rgb(203, 213, 225) dalam keadaan dasar.

Probe otomatis tidak dapat menekan Tab, sehingga demo menyertakan kotak pembanding yang outline-nya selalu aktif dengan nilai yang sama persis dengan aturan :focus-visible.

Menguji dengan Keyboard #

Langkah manual berikut memverifikasi perilaku yang tidak dapat dijangkau probe:

  1. Buka demo, lalu klik tombol dengan mouse — fokus pindah ke tombol (:focus aktif), tetapi cincin umumnya tidak tampil karena browser menilai pengguna pointer tidak memerlukannya.
  2. Tekan Tab beberapa kali — setiap elemen yang menerima fokus menampilkan cincin biru 3px dengan celah 2px.
  3. Klik input teks — cincin tetap tampil: elemen isian selalu memicu :focus-visible karena kursor teks harus terlihat.

Saat menyempurnakan desain, panel DevTools dapat memaksa keadaan fokus tanpa keyboard: pilih elemen di tab Elements, buka menu Force state, lalu centang :focus-visible. Gunakan cara ini untuk iterasi visual, dan simpan pengujian akhir untuk keyboard sungguhan agar urutan Tab ikut diperiksa — fokus sebaiknya berpindah mengikuti urutan visual halaman, bukan melompat ke elemen yang jauh di belakang.