Pengguna yang menavigasi halaman hanya dengan keyboard tidak bisa melihat kursor; satu-satunya petunjuk posisi mereka adalah indikator fokus, biasanya outline di sekeliling elemen. Browser sudah menyediakan gaya bawaan untuk itu, tetapi begitu kita menata tombol dan input sendiri, kita juga bertanggung jawab menata state fokusnya. Pada chapter ini kita membedakan :focus, :focus-visible, dan :focus-within, lalu menyusun indikator fokus yang muncul tepat ketika dibutuhkan.

Tiga Pseudo-class Fokus #

Pseudo-classCocok ketika
:focuselemen menerima fokus, apa pun caranya: klik mouse, tombol Tab, atau kode JavaScript
:focus-visibleelemen menerima fokus dan browser menilai indikator terlihat akan membantu — umumnya karena fokus datang dari keyboard
:focus-withinelemen itu sendiri atau salah satu anaknya sedang menerima fokus

Perbedaan :focus dan :focus-visible adalah kunci chapter ini. Keduanya sama-sama mencocokkan elemen yang terfokus, tetapi :focus-visible menambahkan keputusan browser: fokus yang lahir dari ketukan mouse biasanya tidak dianggap perlu ditandai, sedangkan fokus dari navigasi keyboard tetap ditandai. Browser yang menentukan — kita tinggal menuliskan gayanya.

Menata :focus-visible #

Pseudo-class ini menjadi rekomendasi modern untuk gaya indikator fokus karena sifatnya yang selektif:

css
.tombol-undang {
  background-color: #1f6f54;
  color: #fdfaf3;
  padding: 10px 20px;
  border-radius: 10px;
}

.tombol-undang:focus-visible {
  outline: 2px solid #f4b942;
  outline-offset: 2px;
}

Properti outline dipakai karena berada di luar kotak dan tidak menggeser tata letak, sebagaimana dibahas pada chapter Outline.

Tekan Tab berulang hingga fokus tiba di tombol demo, lalu bandingkan dengan mengklik tombolnya langsung menggunakan mouse:

Untuk input form, gaya fokus biasanya berupa perubahan border ditambah cincin tipis:

css
.kolom-cari:focus-visible {
  border-color: #1f6f54;
  box-shadow: 0 0 0 3px rgb(31 111 84 / 0.25);
}

Karena seluruh browser modern sudah mendukung :focus-visible, kita bisa menjadikannya gaya utama tanpa fallback rumit.

Sering kali efek hover perlu dirasakan pengguna keyboard juga. Alih-alih menulis dua blok aturan yang identik, gabungkan keduanya dalam satu selector group:

css
.tombol-undang:hover,
.tombol-undang:focus-visible {
  background-color: #14503a;
}

Dua pintu masuk, satu gaya — pola ini menjadi standar di chapter-chapter berikutnya ketika tombol menyusun matriks state lengkapnya.

:focus-within untuk Reaksi Elemen Induk #

Kadang yang perlu bereaksi bukan elemen terfokusnya, melainkan pembungkusnya — misalnya kotak form yang seluruh tepinya menyala saat salah satu kolomnya terfokus:

css
.bingkai-form {
  border: 2px solid #d9d2c0;
  border-radius: 12px;
  padding: 14px;
}

.bingkai-form:focus-within {
  border-color: #1f6f54;
}

Pseudo-class ini hanya butuh satu aturan tanpa JavaScript, dan sering dipakai sebagai efek glow pada pembungkus kolom pencarian.

Jangan Hapus Outline Tanpa Pengganti #

Pola yang benar: gaya kustom selalu menyertakan tanda yang setara atau lebih kontras:

css
.tombol-undang:focus {
  outline: none;
}

.tombol-undang:focus-visible {
  outline: 3px solid #f4b942;
  outline-offset: 3px;
}

Catatan pola di atas: outline: none pada :focus menghapus tanda default untuk fokus mouse, lalu :focus-visible memasang tanda kustom untuk fokus keyboard. Selama gaya kustom benar-benar terlihat, pola ini aman; bila ragu, lebih sederhana menata :focus-visible saja dan membiarkan sisanya bawaan browser.

Bandingkan kedua tombol berikut saat diklik mouse dan saat dicapai lewat Tab:

Kesalahan Umum #

KesalahanAkibatnyaPerbaikannya
outline: none tanpa penggantipengguna keyboard kehilangan penunjuk posisiganti dengan gaya :focus-visible yang kontras
Menata hanya :hover tanpa state fokustombol terasa beku bagi pengguna keyboardduplikasi efek hover ke :focus-visible
Menata :focus untuk semua input lalu terganggu oleh cincin saat klikumpan balik terasa berlebihan bagi pengguna mousepindahkan ke :focus-visible

Ringkasan #

:focus mencocokkan semua jenis fokus, :focus-visible membiarkan browser memutuskan kapan indikator dibutuhkan, dan :focus-within membuat pembungkus ikut bereaksi. Kombinasi ketiganya memberi kita kendali penuh atas state yang paling menentukan aksesibilitas. Chapter berikutnya melanjutkan ke state sesaat yang lain: :active, yang muncul hanya selama elemen sedang ditekan.