Kenapa ini penting
Bayangkan sebuah gedung kantor yang pintu masuknya hanya bisa dicapai lewat tangga. Orang yang berjalan normal tidak sadar ada masalah. Tapi pengguna kursi roda, ibu yang mendorong kereta bayi, kurir yang membawa troli, dan kakek yang lututnya sakit semuanya tertahan di bawah. Ramp yang ditambahkan untuk kursi roda ternyata dipakai banyak orang lain juga. Aksesibilitas web (sering disingkat a11y, karena ada 11 huruf antara "a" dan "y") adalah ramp untuk halaman web: memastikan situsmu bisa dipakai sebanyak mungkin orang, apa pun kondisi tubuh, alat, dan situasinya.
Angkanya tidak kecil. Menurut WHO (fact sheet Maret 2023), sekitar 1,3 miliar orang, atau 16% penduduk dunia (1 dari 6 orang), hidup dengan disabilitas yang signifikan. Itu belum menghitung disabilitas sementara (tangan patah, mata baru operasi) dan situasional (layar silau di bawah matahari, menggendong anak sambil memegang HP dengan satu tangan, menonton video di KRL tanpa earphone).
Kenyataannya, web masih jauh dari ramah. Laporan WebAIM Million 2026, yang memindai satu juta homepage terpopuler, menemukan 95,9% homepage punya kegagalan WCAG yang terdeteksi otomatis, rata-rata 56,1 error per halaman. Jenis kesalahan terbanyaknya sederhana sekali: teks kontras rendah (83,9% halaman), gambar tanpa teks alternatif (53,1%), input form tanpa label (51%), link kosong (46,3%), tombol kosong (30,6%), dan dokumen tanpa atribut bahasa (13,5%). Kabar baiknya: semua itu bisa kamu hindari dengan pengetahuan dari materi HTML yang sudah kamu pelajari, ditambah sedikit disiplin.
Ada juga alasan bisnis dan teknis. Halaman yang aksesibel biasanya lebih mudah dibaca mesin pencari (keduanya sama-sama "membaca" struktur HTML), lebih mudah dites otomatis (Playwright dan Testing Library mencari elemen lewat peran dan label, persis seperti screen reader), dan di banyak negara menjadi kewajiban hukum untuk layanan publik.
Konsep inti
Siapa saja penggunanya?
Saat merancang, bayangkan orang-orang ini membuka situsmu:
| Kelompok | Contoh kondisi | Cara mereka memakai web | Yang mereka butuhkan |
|---|---|---|---|
| Penglihatan | Tunanetra, low vision, buta warna | Screen reader, zoom 200-400%, mode kontras tinggi | Teks alternatif, struktur heading, kontras cukup, informasi tidak hanya lewat warna |
| Motorik | Tremor, kelumpuhan, RSI, tangan cedera | Keyboard saja, switch device, voice control | Semua fitur bisa diakses keyboard, target klik cukup besar, fokus terlihat |
| Pendengaran | Tuli, kurang dengar | Membaca teks | Caption dan transkrip untuk video/audio |
| Kognitif | Disleksia, ADHD, gangguan memori | Membaca pelan, butuh waktu | Bahasa jelas, tata letak konsisten, pesan error yang membantu, tanpa batas waktu ketat |
| Sensitif gerak | Gangguan vestibular, epilepsi | Mengaktifkan "kurangi gerakan" di OS | Animasi bisa dimatikan, tidak ada kedipan cepat |
Screen reader: cara "melihat" halaman lewat telinga
Screen reader adalah program yang membacakan isi layar dengan suara sintetis atau mengubahnya ke huruf Braille. Contoh yang bisa kamu coba sendiri: VoiceOver (bawaan macOS dan iOS, nyalakan dengan Cmd+F5 di Mac), NVDA (gratis untuk Windows), Narrator (bawaan Windows), dan TalkBack (bawaan Android).
Yang penting dipahami: screen reader tidak membaca piksel. Ia membaca accessibility tree, yaitu versi "ringkas" dari DOM yang dibuat browser. Setiap node di pohon itu punya:
- role (peran): tombol, link, heading, textbox, checkbox, dan seterusnya.
- name (nama aksesibel): teks yang dibacakan, misalnya "Daftar" untuk tombol atau "Email" untuk input yang punya label.
- state/value (keadaan): tercentang, diperluas, wajib diisi, tidak valid.
Kalau kamu menulis <button>Daftar</button>, browser otomatis mengisi role "button", name "Daftar", dan membuatnya bisa difokus serta diklik dengan Enter atau Spasi. Kalau kamu menulis <div class="btn">Daftar</div>, accessibility tree hanya melihat teks biasa. Screen reader membacanya sebagai "Daftar" saja, tanpa memberi tahu bahwa itu bisa diklik, dan pengguna keyboard tidak bisa mencapainya dengan Tab. Kamu bisa melihat accessibility tree sendiri di Chrome DevTools: buka tab Elements, lalu panel Accessibility di sisi kanan.
Pengguna screen reader jarang membaca halaman dari atas ke bawah. Mereka melompat-lompat: menekan H untuk pindah antar-heading, membuka daftar semua link, atau melompat ke landmark seperti <nav> dan <main>. Karena itu struktur heading yang rapi (satu <h1>, lalu <h2>, <h3> berurutan) seperti daftar isi buku bagi mereka.
WCAG 2.2: standar yang dipakai dunia
WCAG (Web Content Accessibility Guidelines) adalah standar aksesibilitas dari W3C. Versi terbaru yang berstatus W3C Recommendation adalah WCAG 2.2, edisi terkininya terbit 12 Desember 2024. Dibanding 2.1, versi 2.2 menambah sembilan kriteria (misalnya Focus Not Obscured, Target Size (Minimum), Accessible Authentication) dan menghapus satu kriteria lama, 4.1.1 Parsing, karena browser modern sudah menangani HTML yang tidak rapi secara konsisten.
WCAG disusun di atas empat prinsip yang disingkat POUR:
| Prinsip | Pertanyaan yang diajukan | Contoh kriteria |
|---|---|---|
| Perceivable (dapat dipersepsi) | Bisakah semua orang menangkap informasinya? | 1.1.1 teks alternatif untuk gambar, 1.4.3 kontras teks |
| Operable (dapat dioperasikan) | Bisakah semua orang memakainya? | 2.1.1 semua fungsi lewat keyboard, 2.4.7 fokus terlihat |
| Understandable (dapat dipahami) | Apakah isi dan perilakunya bisa dimengerti? | 3.1.1 bahasa halaman, 3.3.2 label atau instruksi pada input |
| Robust (kokoh) | Apakah bisa dibaca beragam alat, termasuk teknologi bantu? | 4.1.2 name, role, value pada komponen |
Di bawah prinsip ada 13 guideline, dan di bawahnya ada success criteria (kriteria sukses) yang bisa dites. Setiap kriteria punya level:
- Level A: syarat paling dasar. Kalau gagal, sebagian orang benar-benar tidak bisa memakai halaman. Contoh: 1.1.1 Non-text Content, 2.1.1 Keyboard, 2.1.2 No Keyboard Trap, 3.3.2 Labels or Instructions.
- Level AA: target yang umum dipakai perusahaan dan regulasi. Contoh: 1.4.3 Contrast (Minimum) (rasio 4.5:1 untuk teks biasa), 2.4.7 Focus Visible, 2.4.11 Focus Not Obscured (Minimum), 2.5.8 Target Size (Minimum) (target minimal 24×24 piksel CSS).
- Level AAA: tingkat tertinggi, tidak selalu bisa dicapai untuk semua jenis konten. Contoh: 2.3.3 Animation from Interactions, 2.4.13 Focus Appearance.
Level bersifat kumulatif. "Memenuhi AA" berarti memenuhi semua kriteria A dan AA. Untuk proyek pertamamu, jadikan WCAG 2.2 level AA sebagai target.
Prinsip utama: semantik dulu
Aturan pertama yang paling berguna bagimu sekarang berasal dari dokumen W3C Using ARIA: kalau ada elemen atau atribut HTML bawaan yang sudah punya makna dan perilaku yang kamu butuhkan, pakai itu, jangan mengubah fungsi elemen lain lalu menambal dengan ARIA. Dalam praktik artinya:
- Butuh sesuatu yang diklik untuk menjalankan aksi? Pakai
<button>. - Butuh sesuatu yang membawa ke halaman lain? Pakai
<a href="...">. - Butuh judul bagian? Pakai
<h2>, bukan<p class="judul-besar">. - Butuh navigasi? Bungkus dengan
<nav>. Konten utama?<main>. - Butuh input? Pakai
<input>dengan<label>yang terhubung.
Elemen bawaan memberimu role, name, fokus keyboard, dan perilaku Enter/Spasi secara gratis. Semua yang kamu bangun sendiri dari <div> harus kamu tulis ulang dengan tangan, dan hampir pasti ada yang terlewat.
Contoh kode
Bandingkan dua versi halaman produk yang tampilannya bisa dibuat persis sama dengan CSS. Versi pertama penuh <div>:
<!-- ❌ Versi "div soup": terlihat oke, tapi tidak bisa dipakai screen reader & keyboard -->
<html>
<body>
<div class="header">
<div class="logo">TokoKita</div>
<div class="menu">
<span onclick="location.href='/produk'">Produk</span>
<span onclick="location.href='/kontak'">Kontak</span>
</div>
</div>
<div class="judul">Sepatu Lari Ringan</div>
<img src="sepatu.jpg">
<div class="harga">Rp 450.000</div>
<div class="btn" onclick="beli()">Beli sekarang</div>
</body>
</html>
Masalahnya: tidak ada lang (screen reader bisa membaca teks Indonesia dengan logat Inggris), menu tidak bisa dijangkau dengan Tab, "judul" bukan heading sehingga tidak muncul di daftar heading, gambar tanpa alt dibacakan sebagai nama filenya ("sepatu titik jpg"), dan "tombol" beli tidak bisa difokus atau ditekan dengan Enter.
<!-- ✅ Versi semantik: CSS bisa membuat tampilannya sama persis -->
<!doctype html>
<html lang="id">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Sepatu Lari Ringan, TokoKita</title>
</head>
<body>
<a class="skip-link" href="#main">Lewati ke konten utama</a>
<header>
<a href="/" class="logo">TokoKita</a>
<nav aria-label="Menu utama">
<ul>
<li><a href="/produk">Produk</a></li>
<li><a href="/kontak">Kontak</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>Sepatu Lari Ringan</h1>
<img src="sepatu.jpg" alt="Sepatu lari warna biru navy dengan sol putih"
width="600" height="400" />
<p class="harga">Rp 450.000</p>
<button type="button" id="beli">Beli sekarang</button>
</main>
<footer>
<p>© 2026 TokoKita</p>
</footer>
<script type="module">
// Perilaku di JS, bukan atribut onclick (lebih rapi & ramah CSP, lihat modul Keamanan)
document.querySelector('#beli').addEventListener('click', () => {
alert('Masuk keranjang!');
});
</script>
</body>
</html>
Coba sendiri: buka versi kedua, lalu tekan Tab berulang kali. Fokus akan berpindah dari skip link, logo, menu, sampai tombol Beli, dan tombol bisa ditekan dengan Enter maupun Spasi tanpa satu baris JavaScript tambahan untuk keyboard. Lalu nyalakan screen reader. Di VoiceOver kamu akan mendengar sesuatu seperti "Sepatu Lari Ringan, heading level 1" dan "Beli sekarang, button".
Kamu juga bisa memeriksa accessibility tree lewat JavaScript di Console DevTools. Ini cara cepat untuk memastikan semua tombol punya nama:
// Tempel di Console: cari tombol & link yang tidak punya teks (penyebab "empty button/link")
const kosong = [...document.querySelectorAll('button, a[href]')].filter((el) => {
const teks = el.textContent.trim();
const label = el.getAttribute('aria-label') || el.getAttribute('aria-labelledby');
const gambarBerAlt = el.querySelector('img[alt]:not([alt=""])');
return !teks && !label && !gambarBerAlt;
});
console.log(`${kosong.length} elemen tanpa nama`, kosong);
// → 0 elemen tanpa nama [] (pada versi semantik)
Kesalahan umum
- Menganggap aksesibilitas hanya untuk tunanetra. Padahal kelompok penggunanya luas: pengguna keyboard, orang tua dengan penglihatan menurun, orang yang memakai HP di bawah terik matahari. Rancang untuk semua kelompok di tabel di atas.
- Mengurus aksesibilitas di akhir proyek. Menambal
divjadi tombol yang aksesibel jauh lebih mahal daripada memakai<button>sejak awal. Jadikan semantik kebiasaan saat menulis HTML pertama kali. - Struktur heading dipilih berdasarkan ukuran huruf. Memakai
<h4>karena "ukurannya pas" merusak daftar isi bagi pengguna screen reader. Pilih level heading sesuai struktur, atur ukuran dengan CSS. - Lupa
langdi<html>. Tanpalang="id", screen reader bisa memakai mesin suara bahasa lain sehingga kalimat Indonesia terdengar kacau. Ini kriteria 3.1.1 level A. - Menganggap skor otomatis 100 berarti aksesibel. Alat otomatis hanya menangkap sebagian masalah (misalnya ada
altatau tidak, bukan apakah isialt-nya masuk akal). Tetap uji manual dengan keyboard dan screen reader.
Latihan
- Mudah, Sebutkan prinsip POUR yang dilanggar oleh masing-masing kasus: (a) video tutorial tanpa caption, (b) menu dropdown yang hanya terbuka saat di-hover mouse, (c) pesan error "Error 422" tanpa penjelasan.
- Sedang, Ubah potongan ini menjadi HTML semantik:
<div class="nav"><div onclick="go('/')">Beranda</div></div><div class="big">Promo Hari Ini</div><div class="kotak">...</div>. - Menantang, Tulis fungsi
cekHeading()yang dijalankan di Console untuk mendeteksi heading yang "meloncat" level (misalnya dari<h2>langsung ke<h4>) dan halaman yang punya lebih dari satu atau tidak punya<h1>.
Lihat solusi
1. (a) Perceivable: informasi audio tidak bisa ditangkap orang tuli. (b) Operable: tidak bisa dipakai lewat keyboard atau layar sentuh. (c) Understandable: pesan tidak menjelaskan apa yang salah dan cara memperbaikinya.
2.
<nav aria-label="Menu utama">
<ul>
<li><a href="/">Beranda</a></li>
</ul>
</nav>
<main>
<h1>Promo Hari Ini</h1>
<section>...</section>
</main>
3.
function cekHeading() {
const headings = [...document.querySelectorAll('h1, h2, h3, h4, h5, h6')];
const masalah = [];
const jumlahH1 = headings.filter((h) => h.tagName === 'H1').length;
if (jumlahH1 !== 1) masalah.push(`Ada ${jumlahH1} <h1>, sebaiknya tepat 1`);
let levelSebelum = 0;
for (const h of headings) {
const level = Number(h.tagName[1]);
if (levelSebelum && level > levelSebelum + 1) {
masalah.push(`Loncat dari h${levelSebelum} ke h${level}: "${h.textContent.trim()}"`);
}
levelSebelum = level;
}
console.log(masalah.length ? masalah : 'Struktur heading rapi ✅');
}
cekHeading();
// → Struktur heading rapi ✅
Ringkasan
- Aksesibilitas memastikan web bisa dipakai semua orang. Sekitar 16% penduduk dunia punya disabilitas signifikan, belum termasuk kondisi sementara dan situasional.
- Screen reader membaca accessibility tree (role, name, state), bukan tampilan visual.
- WCAG 2.2 disusun di atas prinsip POUR, dengan level A, AA, AAA. Target realistis: AA.
- Semantik dulu: elemen HTML bawaan (
button,a,h1-h6,nav,main,label) memberikan aksesibilitas gratis. - Kesalahan paling umum di web nyata sederhana: kontras rendah, gambar tanpa
alt, input tanpa label, link/tombol kosong, tanpalang.