Sejak 36 Navigasi dan Menu kita nyebut “aksesibel” hampir di tiap bab, selalu dengan janji “dibahas di bab 55”. Ini bab-nya. Theme yang aksesibel bisa dipakai semua orang, termasuk yang pakai teknologi bantu, dan itu bukan fitur tambahan, itu syarat Theme Store.
Waktu bikin theme, ambil keputusan desain yang menjaga konten tetap aksesibel. Theme aksesibel didesain biar bisa dipakai semua orang, termasuk yang bergantung ke teknologi bantu (screen reader, keyboard saja, switch, pembesar layar). Praktik di bab ini disusun dengan mengacu ke WCAG (Web Content Accessibility Guidelines) 2.1. Catatan penting dari Shopify: ngikutin daftar ini gak menjamin theme sepenuhnya aksesibel, tapi ini fondasi minimalnya.
Empat Prinsip WCAG
- Perceivable (bisa dipersepsi): informasi dan komponen UI harus bisa disajikan dengan cara yang bisa ditangkap pengguna (teks alternatif buat gambar, caption buat video, kontras cukup).
- Operable (bisa dioperasikan): komponen UI dan navigasi harus bisa dioperasikan (keyboard, tanpa batas waktu ketat, tanpa konten yang memicu kejang).
- Understandable (bisa dipahami): informasi dan cara kerja UI harus bisa dipahami (bahasa jelas, perilaku bisa diprediksi, bantuan buat error).
- Robust (tangguh): konten cukup jelas buat ditafsirkan berbagai user agent termasuk teknologi bantu (HTML valid, ARIA yang benar).
Cara Ngetes
Alat yang disaranin:
- Accessibility Insights for Web, ekstensi browser dari Microsoft, punya mode “FastPass” otomatis dan panduan tes manual.
- Lighthouse, di Chrome DevTools, skor aksesibilitas plus performa.
- WAVE, ekstensi dari WebAIM yang nampilin error langsung di halaman.
Kalau pakai CI, tambahin pengecekan biar perubahan kode gak nurunin skor aksesibilitas secara signifikan, lewat Shopify Lighthouse CI GitHub Action yang ngupload theme ke toko benchmark, ngukur, dan ngitung skornya, dibahas di 68 Theme Inspector dan Lighthouse CI.
Tapi alat otomatis cuma nangkep sekitar 30–40% masalah. Tes manual yang wajib: navigasi seluruh alur beli pakai keyboard aja (Tab, Shift+Tab, Enter, Space, Esc, panah), dan pakai screen reader (VoiceOver di Mac/iOS, NVDA di Windows, TalkBack di Android) minimal buat halaman produk, cart, dan checkout.
Keyboard dan Gestur
Pengguna dengan gangguan penglihatan atau motorik sering pakai keyboard buat navigasi. Mereka bergantung ke indikator visual yang nunjukin di mana fokus keyboard berada. Semua link, tombol, navigasi dropdown, dan kontrol form harus bisa dioperasikan keyboard.
1. Dukungan Keyboard
- Indikator fokus kelihatan dan konsisten di elemen aktif, baik navigasi pakai mouse maupun keyboard.
- Urutan fokus = urutan DOM: atas ke bawah, kiri ke kanan. Jangan pakai CSS
orderataupositionyang bikin urutan visual beda dari DOM. - Style fokus kelihatan di desktop waktu pakai keyboard.
outline: nonetanpa pengganti itu pelanggaran paling umum. - Theme gak bergantung ke hover mouse buat sesuatu jadi kelihatan atau bisa diakses. Dropdown yang cuma muncul waktu hover gak bisa dibuka keyboard, makanya
<details>di 36 Navigasi dan Menu > Dropdown yang Aksesibel. - Tab dan Shift+Tab bisa buat navigasi.
- Gak ada perubahan konteks mendadak waktu elemen dapat fokus. Fokus ke sebuah kontrol gak boleh bikin fokus loncat ke tempat lain, buka modal, atau submit form.
❌ ngilangin outline tanpa pengganti
*:focus { outline: none; }✅ ganti dengan style fokus yang jelas, cuma buat keyboard
:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }2. Dukungan Gestur
- Gestur zoom (pinch to zoom) selalu tersedia.
- Fungsi yang butuh beberapa jari atau gestur rumit (navigasi model 3D dari 40 Produk Media) harus tersedia juga lewat satu ketukan atau klik (tombol putar, zoom).
Struktur Halaman
Theme harus pakai HTML valid, cek pakai W3 HTML checker. HTML yang gak valid ditafsirkan berbeda oleh tiap teknologi bantu.
1. Global
- Atribut
langdi elemenhtml, biar screen reader ngucapin konten dengan aksen dan dialek yang benar:<html lang="{{ request.locale.iso_code }}">. - Zoom viewport aktif: jangan pakai
maximum-scaledanuser-scalable="no"di meta viewport. Pengguna dengan penglihatan rendah butuh zoom. - Skip link tersedia dan kelihatan waktu difokus, buat lompat ke konten utama melewati header. Wadah konten utama dikasih
tabindex="-1"biar bisa nerima fokus:
<a class="skip-to-content-link visually-hidden" href="#MainContent">{{ 'accessibility.skip_to_text' | t }}</a>
...
<main id="MainContent" tabindex="-1">- Alur konten linear: gak ada
tabindexselain0atau-1, dan gak adaautofocus.tabindexpositif dan autofocus ngambil kendali dari pengguna dengan memaksa urutan fokus tertentu. Biarin pengguna nemuin konten secara alami.
❌ nonaktifin zoom
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">✅ zoom bebas
<meta name="viewport" content="width=device-width, initial-scale=1">2. Heading
- Heading pakai markup heading (
h1sampaih6) buat nyampein struktur konten. Screen reader punya mode navigasi per heading. - Heading dipakai berurutan. Bukan buat desain (jangan pakai
h3cuma karena ukurannya pas), tapi buat urutan logis konten. Atur ukurannya lewat class. h1buat topik utama halaman, satu per halaman (judul produk di halaman produk, judul koleksi di halaman koleksi). Ini juga penting buat SEO dari 48 SEO Metadata, hreflang, robots.txt.
Di theme dengan section yang bebas diurutin, ini tantangan: section “Featured collection” gak tau dia di bawah h1 atau bukan. Solusinya: kasih setting level heading di section, atau pakai h2 konsisten buat judul section karena h1 selalu di section utama.
3. Navigasi
- Area navigasi dibungkus
<nav>. aria-currentbuat nyampein halaman sekarang waktu menelusuri link (aria-current="page"dari bab 36).role="menu"ataurole="menuitem"gak dipakai buat navigasi. Role itu buat menu aplikasi (kaya menu bar desktop) dengan pola keyboard panah yang berbeda, dan bikin screen reader ngasih instruksi yang salah buat navigasi situs biasa.
4. Dropdown Navigasi
aria-expandedbuat nyampein state navigasi yang bisa dilipat.aria-controlsbuat ngasih tau teknologi bantu ada wadah tersembunyi yang dikontrol dropdown itu.aria-currentbuat lokasi/halaman sekarang.- Enter dan Space buka dropdown, dan fokus tetap di kontrol pembuka. Tab mindahin fokus ke item pertama dropdown.
- Esc nutup dropdown dan ngembaliin fokus ke pembuka.
5. Informasi Produk
- Gambar produk punya alt text deskriptif (dari
image.altyang diisi merchant, lewatimage_tag). - Harga diskon dan reguler dibedain secara visual dan lewat markup buat screen reader. Pakai teks visually-hidden buat ngebedain: tanpa itu, screen reader baca “40” tanpa tau mana yang mana.
<span class="visually-hidden">{{ 'products.product.price.regular_price' | t }}</span>
<s>{{ product.compare_at_price | money }}</s>
<span class="visually-hidden">{{ 'products.product.price.sale_price' | t }}</span>
{{ product.price | money }}- Kalau theme ngubah harga dan ketersediaan secara dinamis waktu varian dipilih (39 Produk Variants dan High-variant Products), perubahannya harus disampaikan ke screen reader.
aria-livebuat nyampein perubahan UI dinamis. Regionaria-live="polite"yang isinya diupdate (“Harga sekarang $40, tersedia”) bakal dibacain tanpa ngeganggu. Ini yang ada di sectioncart-live-region-textDawn dari 51 Ajax API dan Section Rendering API.
6. Kontrol
<a>buat link: navigasi, muat halaman baru, atau mindahin fokus keyboard dari satu elemen ke elemen lain.<button>buat aksi di layar: buka modal, urutin tabel, buka drawer.<a href="#">dengan handler klik itu salah, screen reader ngumumin “link” dan pengguna nyangka bakal pindah halaman.- Tujuan link jelas dari teksnya sendiri. “Klik di sini” atau “Selengkapnya” tanpa konteks gak berguna di daftar link screen reader. Pakai “Selengkapnya tentang [nama produk]” (bisa visually-hidden).
- Link yang buka jendela baru punya peringatan: ikon visual dengan teks alternatif biar pengguna screen reader dan pengguna keyboard tau bakal buka jendela baru.
❌ tombol yang pura-pura link
<a href="#" onclick="openCart()">Cart</a>✅ tombol beneran
<button type="button" aria-controls="CartDrawer" aria-expanded="false">Cart</button>7. Tabel
<table>buat data tabular (bukan buat layout, dan sebaliknya jangan pakaidivbuat data tabular kaya size chart).<caption>biar teknologi bantu tau ada tabel yang lagi dibaca.<th>buat header dengan atributscope:scope="col"buat header kolom,scope="row"buat header baris.
8. Form
- Semua field punya label:
aria-label, elemen.visually-hidden, floating label, atau label kelihatan. Nama input dan kontrol jelas tujuannya. - Label pakai atribut
foryang nunjuk keidinput, termasuk label form di theme setting (form yang dirender dari setting merchant tetap harus punyafor/idyang cocok). - Input wajib punya atribut
required. - Field pakai atribut
autocomplete(email,given-name,postal-code), biar browser bisa ngisi dari data tersimpan. Ini bantu banget pengguna dengan gangguan motorik.
9. Error Form
- Fokus dipindah ke pesan umpan balik. Error hasil submit form disampaikan ke screen reader secepat mungkin. Tanpa ini, pengguna screen reader klik submit dan gak tau apa-apa terjadi.
- Pesan error jelas dan deskriptif (“Email harus berisi @”, bukan “Input tidak valid”).
aria-describedbydi input yang ngerujuk ke wadah teks error, biar waktu fokus ke input, errornya dibacain.- Notifikasi, pesan error, pesan sukses diumumkan lewat
aria-live.
<label for="ContactEmail">Email</label>
<input type="email" id="ContactEmail" name="contact[email]" autocomplete="email" required
{% if form.errors contains 'email' %}aria-invalid="true" aria-describedby="ContactEmail-error"{% endif %}>
{% if form.errors contains 'email' %}
<p id="ContactEmail-error" role="alert">{{ form.errors.messages['email'] }}</p>
{% endif %}Media
Media bisa mengganggu, mengacaukan, atau tak terduga. Aturannya:
- Media gak autoplay.
- Kontrol media pakai elemen HTML native: tombol dengan state toggle,
input type="range"buat slider. - Media bisa di-pause pakai Space.
1. Gambar dan Ikon
- Semua
<img>punya atributalt. Tanpaalt, screen reader bacain nama dan path file gambar (“IMG underscore 4521 dot jpg”), yang bikin frustrasi. - Gambar produk atau konten punya alt yang mendeskripsikan gambarnya.
image_tagdari 19 Filters HTML, URL, Media, Color, dan Font > 2. image_tag otomatis ngisi dariimage.alt. - Gambar dekoratif pakai
alt=""(kosong, bukan dihapus) biar disembunyiin dari screen reader. Ikon SVG inline dekoratif pakaiaria-hidden="true".
❌ tanpa alt, screen reader baca nama file
<img src="{{ 'divider.png' | asset_url }}">✅ dekoratif, disembunyiin
<img src="{{ 'divider.png' | asset_url }}" alt="">2. Video
- Closed caption tersedia.
- Deskripsi audio tersedia.
- Kalau autoplay diperlukan (video di slideshow), suaranya bisu, sejalan sama 40 Produk Media > Parameter Video.
- Video dengan audio gak ditutupi secara visual.
- Space buat pause/play.
3. Audio
- Transkrip tersedia.
- Audio autoplay bisa di-pause.
Warna dan Kontras
Teks harus aksesibel buat merchant dan pembeli yang buta warna atau punya gangguan penglihatan lain, yang bergantung ke kontras yang cukup buat ngebedain satu hal dari yang lain. Cek pakai contrast ratio tool. Aturannya:
- Teks kurang dari 24px (reguler) atau 18.5px (bold): rasio kontras 4.5:1 terhadap latarnya.
- Teks 24px (reguler) atau 18.5px (bold) ke atas: rasio 3.0:1.
- Ikon: 3.0:1 terhadap latarnya.
- Border input: 3.0:1 terhadap latarnya.
- Warna bukan satu-satunya indikator buat nyampein informasi. Field error merah harus juga punya ikon atau teks. Link di paragraf harus punya garis bawah, bukan cuma warna beda.
Tantangannya di theme: merchant yang milih warna lewat theme setting. Jadi theme gak bisa menjamin kontras, tapi bisa membantu: default yang kontras, dan filter color_contrast dari 19 Filters HTML, URL, Media, Color, dan Font > 3. Aksesibilitas buat ngecek atau nyesuain warna teks otomatis terhadap latar yang dipilih merchant. Sistem warna yang dirancang buat ini dibahas di 56 Design dan Color System.
Komponen Dinamis
Slideshow, predictive search, modal, dan tab itu kompleks dan susah dinavigasi. Pakai elemen yang bisa ditafsirkan screen reader, kasih konteks, dan sertakan fungsi keyboard.
1. Drawer dan Modal
- Waktu drawer atau modal dibuka, fokus dipindah ke elemen yang melabeli drawer/modal itu (judulnya).
- Navigasi keyboard tetap di dalam drawer/modal yang terbuka (focus trap). Tab di elemen terakhir balik ke elemen pertama, bukan ke halaman di belakangnya.
- Esc nutup drawer/modal dan ngembaliin fokus ke elemen pembuka.
- Role buat modal adalah
dialog(denganaria-modal="true"danaria-labelledby), kaya modal pickup di 49 Delivery Pickup Availability.
Elemen <dialog> native browser ngasih focus trap, Esc, dan role otomatis lewat showModal(), dan sekarang didukung semua browser modern. Ini pilihan pertama sebelum bikin sendiri.
2. Slideshow
- Konten yang berputar otomatis bisa di-pause atau dihentikan.
- Konten slideshow bisa diakses lewat tombol next dan previous (bukan cuma swipe, sejalan sama 40 Produk Media > 5. Slideshow).
Layar Sentuh dan Mobile
Pertimbangan utamanya: merchant/pembeli bisa ganti orientasi dengan mudah dan mengetuk target buat navigasi. Target sentuh kontrol dan link utama minimal 44×44 piksel. Yang termasuk utama:
- Link menu utama, di tingkat manapun.
- Tombol submit form apapun: kontak, komentar, pencarian, add to cart.
- Tombol cart dan hamburger.
- Tombol tutup modal.
- Varian dan opsi di halaman produk: warna, ukuran, kuantitas (swatch warna kecil 20px itu pelanggaran umum).
Checklist Cepat
Buat dipakai sebelum ngirim theme:
langdihtml, viewport tanpa batas zoom, skip link,maindengantabindex="-1".- Satu
h1, heading berurutan,navbuat navigasi, tanparole="menu". - Semua interaktif bisa Tab, fokus kelihatan (
:focus-visible), urutan = DOM, tanpatabindexpositif/autofocus. - Dropdown:
aria-expanded,aria-controls, Enter/Space buka, Esc tutup dan balikin fokus. <a>buat navigasi,<button>buat aksi, teks link jelas, peringatan jendela baru.- Semua
imgpunyaalt(kosong buat dekoratif), harga diskon dengan teks tersembunyi, perubahan dinamis lewataria-live. - Form: label
for/id,required,autocomplete, error dengan fokus,aria-describedby,aria-live. - Media tanpa autoplay (atau bisu), kontrol native, Space buat pause, caption dan transkrip.
- Kontras 4.5:1 teks kecil, 3:1 teks besar/ikon/border, warna bukan satu-satunya sinyal.
- Modal
dialogdengan focus trap dan Esc, slideshow bisa pause dan punya tombol. - Target sentuh 44×44px.
- Tes: Lighthouse/WAVE/Accessibility Insights, keyboard aja, screen reader.
Ringkasan
- Aksesibilitas = WCAG: perceivable, operable, understandable, robust. Daftar ini fondasi, bukan jaminan.
- Tes dengan Accessibility Insights, Lighthouse, WAVE, Lighthouse CI, plus keyboard dan screen reader manual.
- Keyboard: fokus kelihatan, urutan = DOM, tanpa bergantung hover, Tab/Shift+Tab, tanpa perubahan konteks mendadak. Gestur: zoom selalu ada, gestur rumit punya alternatif satu ketukan.
- Struktur: HTML valid,
lang, zoom aktif, skip link +tabindex="-1", tanpatabindexpositif/autofocus, heading berurutan dengan satuh1,nav+aria-currenttanparole="menu", dropdown denganaria-expanded/aria-controls/Enter/Space/Esc. - Produk: alt deskriptif, harga diskon dibedain lewat teks tersembunyi, perubahan varian lewat
aria-live. - Kontrol:
abuat link,buttonbuat aksi, teks link jelas, peringatan jendela baru. Tabel:caption,thdenganscope. - Form: label,
for,required,autocomplete; error dengan fokus, deskriptif,aria-describedby,aria-live. - Media: tanpa autoplay, kontrol native, Space;
altdi semua gambar (alt=""dekoratif); caption, deskripsi audio, transkrip. - Kontras: 4.5:1 (<24px/18.5px bold), 3:1 (lebih besar, ikon, border input), warna bukan satu-satunya indikator.
- Drawer/modal: fokus ke label, focus trap, Esc balikin fokus,
role="dialog". Slideshow: bisa pause, tombol next/prev. - Mobile: target sentuh utama ≥ 44×44px.
Bab selanjutnya kita bahas desain theme: prinsip desain Shopify buat theme, sistem warna berbasis color scheme yang bikin merchant bisa ngatur warna dengan aman, dan cara ngerender-nya ke CSS variable.