IlmHamroh
JavaScript Full-stack/4-qism. HTML77/86-dars19 daqiqa
Mundarija (45)

ARIA Authoring Practices (APG): tabs, akkordeon, menyu tugmasi va combobox

Qisqacha: APG (ARIA Authoring Practices Guide) — W3C'ning tabs, akkordeon, menyu tugmasi, combobox kabi murakkab vidjetlar uchun tayyor "retseptlar" to'plami. Har bir retseptda uch narsa bor: qaysi role va aria-* atributlar qo'yiladi, klaviaturada qaysi tugma nima qiladi va namuna kod. Avval native element (details, dialog, select) yetarlimi — shuni tekshiring. ARIA faqat vidjetning "ismini" aytadi, xatti-harakatini esa JavaScript yozadi.

Bu darsda

  • APG nima ekanini va undan qanday foydalanishni bilasiz.
  • Vidjet uchun avval native element, keyin ARIA pattern tanlay olasiz.
  • Tabs, akkordeon, menyu tugmasi va combobox'ning HTML/ARIA tuzilmasini yoza olasiz.
  • Roving tabindex va aria-activedescendant farqini tushuntira olasiz.
  • role="menu" ni sayt navigatsiyasiga qo'yish nega xato ekanini bilasiz.

Oldin bilishingiz kerak: ARIA asoslari, Klaviatura va fokus boshqaruvi, Jonli hududlar va dinamik kontent, details va summary.

1. Nega bu kerak?

O'tgan darsda sahifada paydo bo'lgan xabarni ekran o'quvchiga aytdirishni o'rgandik. Endi murakkabroq vazifa.

details va summary darsida «Bahor» menyusini akkordeon qilgan edik. Endi dizayner uni qayta chizib keldi. Tepada uchta yorliq: "Issiq taomlar", "Salatlar", "Ichimliklar". Bittasini bossangiz, pastda faqat o'sha bo'lim ko'rinadi. Yonida taom qidirish maydoni, yozishingiz bilan takliflar chiqadi.

Muammo: HTML'da <tabs> degan teg yo'q. Combobox tegi ham yo'q. Dasturchi bularni div va button lardan o'zi yig'adi. «Bahor»ning doimiy mehmoni Malika NVDA ekran o'quvchisi bilan ishlaydi. U bu yig'ilgan narsani qanday "ko'radi"? Qaysi tugmani bosishi kerak?

Har dasturchi buni o'zicha hal qilsa, har saytda boshqacha bo'ladi. Malika har yangi saytda qaytadan o'rganishga majbur. Yo'l belgilarini eslang: ular dunyoning ko'p davlatida bir xil. Haydovchi notanish shaharda ham "STOP" belgisini taniydi. APG — vidjetlar uchun shunday umumiy "yo'l belgilari".

2. APG nima?

2.1 Retseptlar kitobi

APG (ARIA Authoring Practices Guide) — W3C'ning accessibility bo'limi (WAI) chiqargan qo'llanma. Manzili: w3.org/WAI/ARIA/apg. Unda 30 ga yaqin pattern (andoza) bor. Pattern — tez-tez uchraydigan vidjetni to'g'ri qurishning kelishilgan usuli.

Har bir pattern sahifasi bir xil tuzilgan:

Bo'lim Nima yozilgan
About This Pattern Vidjet nima va qachon ishlatiladi
Keyboard Interaction Qaysi tugma nima qiladi
Roles, States, and Properties Qaysi role va aria-* kerak
Examples Ishlaydigan namuna (HTML + CSS + JS)

Ekran o'quvchilar va brauzerlar aynan shu kelishuvga moslashgan. Siz patternga amal qilsangiz, Malika sizning tablaringizni boshqa saytdagi tablar kabi boshqaradi.

2.2 Asosiy ogohlantirish: ARIA xatti-harakat bermaydi

ARIA asoslari darsidagi fikrni eslang: ARIA faqat va'da beradi. role="tab" yozsangiz, ekran o'quvchi "tab" deb e'lon qiladi. Malika o'ng strelkani bosadi va keyingi tabga o'tishni kutadi. JavaScript yozilmagan bo'lsa, hech narsa bo'lmaydi.

Ya'ni yarim ish qilingan vidjet ARIA'siz vidjetdan ham yomonroq: u yolg'on va'da beradi. APG'ning kirish sahifasi ham shuni aytadi: "ARIA'siz yaxshi, yomon ARIA'dan ko'ra".

Bu darsda har patternning HTML va ARIA qismini yozamiz va klaviatura qoidalarini o'rganamiz. Tugmalarni "jonlantiradigan" JavaScript — keyinroq, Dinamik UI'da qulaylik darsida. CSS tomoni — Tabs va accordion darsida.

Tekshirib ko'ring: Dasturchi div larga role="tab" va aria-selected qo'ydi, lekin JavaScript yozmadi. Ekran o'quvchi foydalanuvchisi uchun natija qanday?

Javob

Yomon. Ekran o'quvchi "tab, 3 dan 1" deb e'lon qiladi — foydalanuvchi strelkalar ishlaydi deb o'ylaydi. Strelkalar esa hech narsa qilmaydi, tanlangan tab ham o'zgarmaydi. Rol va'da berdi, lekin uni bajaradigan kod yo'q.

3. Birinchi qadam: native element yetarlimi?

3.1 Qaror jadvali

ARIA'ning birinchi qoidasi: mos HTML element bo'lsa — o'shani ishlating. Native elementda klaviatura, fokus va ekran o'quvchi bilan ishlash tayyor, bepul. Ko'p APG patternlarining HTML'da tayyor muqobili bor:

Vidjet Native muqobil ARIA kerakmi?
Disclosure (ochiladigan blok) details + summary Deyarli hech qachon
Akkordeon (bittasi ochiq) details name="..." Kamdan-kam
Modal oyna dialog Yo'q
Tanlash ro'yxati select Yo'q
Takliflar bilan maydon input + datalist Ba'zan
O'chirgich (switch) input type="checkbox" Yo'q
Tabs yo'q Ha
Menyu tugmasi popover qisman Ha
Karusel yo'q Ha

details ni details va summary, dialog ni dialog, datalist ni tanlash maydonlari darsida o'rgandik.

3.2 Native akkordeon — ARIA'siz

details va summary darsidagi «Bahor» menyusini eslang. Uchta details bir xil name="menyu" bilan — va bir vaqtda faqat bittasi ochiq. Bu APG'ning akkordeon patternining aynan o'zi.

Farqi — unda bitta ham aria- atributi va bitta ham qator JavaScript yo'q. Klaviatura (Tab, Enter, Space), "ochiq/yopiq" holati, ekran o'quvchi e'loni — hammasini brauzer o'zi beradi. APG patternini qo'lda yig'sangiz, shu ishlarning hammasini o'zingiz yozasiz.

Demak, dizayner tablarni chizgan bo'lsa ham, avval so'raymiz: "akkordeon ham yaraydimi?". Yaraydigan bo'lsa — native qoladi. Bizning holatda buyurtmachi aynan tablarni xohladi. Shuning uchun davom etamiz.

Maslahat: html-validate'da prefer-native-element degan qoida bor. role="button" yoki role="listbox" ko'rsa, "native button / select ni ishlating" deb xato beradi. Bu — ARIA'ning birinchi qoidasi, vositaga aylantirilgan.

Tekshirib ko'ring: Mijoz "Batafsil" tugmasini bosganda taom tarkibi ochilishini xohlaydi. Qaysi pattern va qaysi HTML?

Javob

Bu disclosure (ochiladigan blok) patterni. Eng yaxshi yechim — details va summary: summary ichida "Tarkibi", details ichida tarkib ro'yxati. ARIA ham, JavaScript ham kerak emas.

4. Fokus guruh ichida qanday yuradi

Murakkab vidjetlarda fokus ikki xil usulda boshqariladi. Patternlarni o'qishdan oldin ikkalasini tanib oling.

4.1 Roving tabindex

APG'ning umumiy qoidasi: vidjet — bitta Tab to'xtashi. Tab guruhga bir marta kiradi, guruh ichida esa strelkalar yuradi. O'nta tabdan o'tish uchun Tab ni o'n marta bosish kerak bo'lmasin.

Buning usulini Klaviatura va fokus darsida filtr tugmalari misolida ko'rgan edik — roving tabindex (ko'chib yuruvchi tabindex):

  • faol elementda tabindex="0" — Tab shunga tushadi;
  • qolganlarida tabindex="-1" — Tab ularni o'tkazib yuboradi;
  • strelka bosilganda JavaScript 0 ni keyingi elementga ko'chiradi va fokusni unga beradi.

Estafeta tayoqchasiga o'xshaydi: jamoada to'rt yuguruvchi bor, lekin tayoqcha bittasining qo'lida. O'sha darsda "to'liq pattern rollar bilan keyinroq" degan edik — mana, o'sha payt keldi.

4.2 aria-activedescendant

Combobox'da boshqa muammo bor. Malika maydonga "osh" deb yozyapti, pastda takliflar chiqdi. U strelka bilan takliflar bo'ylab yuradi — lekin yozishni davom ettirishi ham kerak. Fokus maydondan ketib qolsa, yozib bo'lmaydi.

Yechim — aria-activedescendant ("faol avlod"). Haqiqiy fokus maydonda qoladi. Atribut esa ro'yxatdagi qaysi band "hozir tanlangan"ini id orqali ko'rsatadi:

html
<input id="taom-qidir" type="text" role="combobox"
       aria-activedescendant="taklif-2" ...>

Ekran o'quvchi taklif-2 elementini xuddi fokus unda turgandek o'qiydi.

Roving tabindex aria-activedescendant
Haqiqiy fokus Band o'zida Konteyner yoki maydonda
Qayerda Tabs, menyu, toolbar Combobox, listbox
JS nima qiladi tabindex ni ko'chiradi id ni almashtiradi

4.3 Ekran o'quvchi strelkalarni kimga beradi?

Bir mayda, lekin muhim detal. NVDA kabi ekran o'quvchilar oddiy sahifada strelkalarni o'zi ishlatadi — matnni qatorma-qator o'qish uchun. Sahifa strelka bosilganini bilmaydi ham.

Fokus role="tablist", menu yoki listbox ichiga tushganda, ekran o'quvchi "bu vidjet, strelkalarni unga beraman" deb fokus rejimiga o'tadi. Ya'ni to'g'ri rol — sizning JavaScript'ingiz strelkani umuman "eshitishi" uchun ham kerak.

5. Tabs

5.1 Qachon tabs — va qachon emas

Tabs — bir joyda bir nechta panel, bir vaqtda faqat bittasi ko'rinadi. Panellar qisqa va teng huquqli bo'lganda mos keladi: menyu bo'limlari, "Tavsif / Tarkib / Sharhlar".

Tabga o'xshagan, lekin alohida sahifalarga olib boradigan yorliqlar esa tabs emas. Ular — navigatsiya: nav ichidagi havolalar va faol sahifada aria-current="page". Buni ko'p sahifali sayt darsida qilgan edik. Havola bosilsa URL o'zgaradi, tab bosilsa — o'zgarmaydi. Mana shu farq.

5.2 HTML va ARIA tuzilmasi

«Bahor» menyusining uchta bo'limi:

html
<div role="tablist" aria-label="Menyu bo'limlari">
  <button type="button" role="tab" id="tab-issiq"
          aria-selected="true"
          aria-controls="panel-issiq">Issiq taomlar</button>
  <button type="button" role="tab" id="tab-salat"
          aria-selected="false" tabindex="-1"
          aria-controls="panel-salat">Salatlar</button>
  <button type="button" role="tab" id="tab-ichimlik"
          aria-selected="false" tabindex="-1"
          aria-controls="panel-ichimlik">Ichimliklar</button>
</div>

<div role="tabpanel" id="panel-issiq"
     aria-labelledby="tab-issiq" tabindex="0">
  <ul>
    <li>Osh — 35 000</li>
    <li>Lag'mon — 28 000</li>
  </ul>
</div>
<div role="tabpanel" id="panel-salat"
     aria-labelledby="tab-salat" tabindex="0" hidden>
  <ul>
    <li>Achchiq-chuchuk — 12 000</li>
    <li>Vinegret — 15 000</li>
  </ul>
</div>
<div role="tabpanel" id="panel-ichimlik"
     aria-labelledby="tab-ichimlik" tabindex="0" hidden>
  <ul>
    <li>Ko'k choy (choynak) — 5 000</li>
    <li>Kompot (1 litr) — 8 000</li>
  </ul>
</div>

Qatorma-qator:

  • role="tablist" — "bu tablar guruhi". aria-label guruhga nom beradi: ekran o'quvchi "Menyu bo'limlari, tab ro'yxati" deydi.
  • button + role="tab" — nega div emas? button fokus oladi va Enter/Space ni o'zi tushunadi. Yarim ish tayyor.
  • aria-selected="true" — hozir tanlangan tab. Qolganlarida "false".
  • tabindex="-1" — tanlanmagan tablarda. Bu — roving tabindex: Tab faqat tanlangan tabga tushadi.
  • aria-controls — "bu tab qaysi panelni boshqaradi", panelning id si.
  • role="tabpanel" + aria-labelledby — panelning nomi uning tabidan olinadi: "Issiq taomlar, tab paneli".
  • tabindex="0" panelda — panel ichida havola yoki tugma bo'lmasa, Tab panelning o'ziga tushsin. Aks holda Malika tabdan keyin to'g'ridan-to'g'ri sahifaning keyingi qismiga "sakrab" ketadi.
  • hidden — ko'rinmaydigan panellar. Tab almashganda JavaScript uni olib tashlaydi.

Ekran o'quvchi ikkinchi tabda taxminan shunday deydi: "Salatlar, tab, tanlanmagan, 3 dan 2". Tartib raqamini ("3 dan 2") brauzer DOM'dan o'zi hisoblaydi.

5.3 Klaviatura

Tugma Nima bo'ladi
Tab Tanlangan tabga kiradi; keyingi Tab — panelga
→ / ← Keyingi / oldingi tab (oxiridan boshiga aylanadi)
Home / End Birinchi / oxirgi tab
Enter / Space Tabni faollashtiradi (qo'lda rejimda)

APG ikki rejimni tasvirlaydi. Avtomatik rejimda strelka bosilishi bilan panel ham almashadi. Qo'lda rejimda strelka faqat fokusni ko'chiradi, panel Enter dan keyin almashadi. Panel tez chiqsa — avtomatik, har tab serverdan yuklansa — qo'lda. Tablar vertikal joylashsa, aria-orientation="vertical" qo'yiladi va ↑/↓ ishlaydi.

5.4 JavaScript nima qiladi

Kod keyinroq, lekin vazifalar ro'yxati hozirdan aniq. Tab almashganda JavaScript:

  1. yangi tabda aria-selected="true", eskisida "false" qiladi;
  2. tabindex ni ko'chiradi: yangisida 0, eskisida -1;
  3. yangi panelning hidden ini olib tashlaydi, eskisiga qo'yadi;
  4. strelka bosilganda fokusni yangi tabga beradi.

Uchta atribut va bitta fokus. Ro'yxatning birortasi unutilsa, vidjet "yolg'on" gapira boshlaydi.

Tekshirib ko'ring: Nega tanlanmagan tablarda tabindex="-1" turibdi? Olib tashlasak nima bo'ladi?

Javob

Olib tashlasak, har bir tab alohida Tab to'xtashi bo'ladi: Malika vidjetdan o'tish uchun Tab ni uch marta bosadi. APG qoidasi — vidjet bitta to'xtash, ichida strelkalar. tabindex="-1" tablarni Tab tartibidan chiqaradi, lekin JavaScript ularga fokusni baribir bera oladi.

6. Akkordeon va disclosure — ARIA varianti

6.1 Qachon details yetmaydi

90% holatda details yetadi. ARIA varianti kerak bo'ladigan holatlar kam: masalan, dizayn tizimi hamma bo'limlar birdaniga ochilishini boshqarishi yoki tugma sarlavha ichida turishi shart bo'lsa.

APG akkordeoni shunday tuziladi:

html
<h3>
  <button type="button" aria-expanded="false"
          aria-controls="tarkib-osh" id="tugma-osh">
    Osh tarkibi
  </button>
</h3>
<section id="tarkib-osh" aria-labelledby="tugma-osh" hidden>
  <p>Guruch, sabzi, mol go'shti, zig'ir yog'i.</p>
</section>
  • button sarlavha ichida. Ekran o'quvchi foydalanuvchilari sahifani sarlavhalar bo'yicha aylanadi. Tugma sarlavhada tursa, har bo'lim sarlavhalar ro'yxatida ko'rinadi.
  • aria-expanded — ochiq ("true") yoki yopiq ("false"). JavaScript uni hidden bilan birga almashtiradi.
  • section + aria-labelledby — APG panelga role="region" berishni taklif qiladi. Nomli section esa shu rolni o'zi oladi — article, section yoki div darsida ko'rgandik. Yana native element g'alaba qildi: div role="region" yozsangiz, html-validate "native section ni ishlating" deydi. Bo'limlar oltitadan ko'p bo'lsa, hudud (region) qilmang — ular hududlar ro'yxatini to'ldirib yuboradi.

Klaviatura: Enter va Space — ochish/yopish, Tab — keyingi tugma. Bu tugmaning o'z xatti-harakati — ARIA'siz ham ishlaydi.

6.2 Mobil menyu — bu disclosure

Telefonda «Bahor» saytining menyusi ☰ tugmasi ortida yashiringan. Tugma bosilsa — havolalar ro'yxati ochiladi. Bu disclosure:

html
<nav aria-label="Asosiy">
  <button type="button" aria-expanded="false"
          aria-controls="asosiy-menyu">Menyu</button>
  <ul id="asosiy-menyu" hidden>
    <li><a href="/">Bosh sahifa</a></li>
    <li><a href="/menyu.html">Taomlar</a></li>
    <li><a href="/bron.html">Stol band qilish</a></li>
  </ul>
</nav>

Oddiy ro'yxat, oddiy havolalar, bitta aria-expanded. Qolgan hamma narsani Tab va Enter o'zi qiladi.

7. Menyu tugmasi (menu button)

7.1 "Menyu" so'zining ikki ma'nosi

Diqqat: ARIA'dagi role="menu" — sayt menyusi emas! U kompyuter dasturlaridagi menyu: "Fayl → Saqlash, Chop etish". Ya'ni amallar ro'yxati. role="menu" qo'yilgan joyda ekran o'quvchi strelkalar bilan boshqaruvni kutadi va Tab ishlamaydi deb hisoblaydi. Sayt navigatsiyasiga qo'ysangiz, Malika havolalarga yetib bora olmay qoladi.

Qoida oddiy: havolalar ro'yxati — nav, amallar ro'yxati — menu.

7.2 Tuzilma

«Bahor» admin panelida har buyurtma yonida "Amallar" tugmasi bor. U ochadigan ro'yxatda uchta amal: takrorlash, chekni yuklab olish, bekor qilish. Bu — haqiqiy menyu:

html
<button type="button" id="amal-tugma"
        aria-haspopup="true" aria-expanded="false"
        aria-controls="amal-menyu">Amallar</button>
<ul role="menu" id="amal-menyu"
    aria-labelledby="amal-tugma" hidden>
  <li role="menuitem" tabindex="-1">Takrorlash</li>
  <li role="menuitem" tabindex="-1">Chekni yuklab olish</li>
  <li role="menuitem" tabindex="-1">Bekor qilish</li>
</ul>
  • aria-haspopup="true" — "bu tugma menyu ochadi". "menu" qiymati ham xuddi shu ma'noni beradi. Ekran o'quvchi "Amallar, menyu tugmasi" deydi.
  • aria-expanded — menyu ochiqmi.
  • role="menu" va role="menuitem" — ro'yxat va uning bandlari. li ning o'z ma'nosi ("ro'yxat bandi") rol bilan almashtirildi.
  • tabindex="-1" — bandlarga faqat JavaScript fokus beradi.

7.3 Klaviatura

Tugma Qayerda Nima bo'ladi
Enter, Space, ↓ Tugmada Menyuni ochadi, birinchi bandga fokus
↑ Tugmada Menyuni ochadi, oxirgi bandga fokus
↓ / ↑ Menyuda Keyingi / oldingi band
Home / End Menyuda Birinchi / oxirgi band
Esc Menyuda Yopadi, fokus tugmaga qaytadi
Harf Menyuda Shu harf bilan boshlanadigan band

Oxirgi qator — "typeahead" (yozib qidirish): B bosilsa "Bekor qilish" ga o'tadi. Esc dan keyin fokusni tugmaga qaytarish — Klaviatura va fokus darsidagi "fokusni qaytarish" qoidasining o'zi.

7.4 Popover yordam beradimi?

Popover API ochish, yopish va Esc bilan yopishni JavaScript'siz beradi. Bu menyuning yarmi. Lekin strelkalar, typeahead va rollarni popover bermaydi. Shuning uchun real hayotda popover + ARIA + kichik JavaScript birga ishlaydi.

Tekshirib ko'ring: Sayt sarlavhasida "Biz haqimizda", "Menyu", "Aloqa" havolalari bor. Dasturchi ularni role="menu" ichiga soldi. Nima deysiz?

Javob

Xato. Bu amallar emas, havolalar — demak, nav ichidagi oddiy ro'yxat. role="menu" ekran o'quvchini "strelkalar bilan boshqariladigan dastur menyusi" deb aldaydi va JavaScript yozilmagan bo'lsa, foydalanuvchi havolalarga yetib bora olmaydi.

8. Combobox

8.1 Avval native variantlar

Combobox — matn maydoni va unga ulangan ochiladigan takliflar ro'yxati. Kundalik misol — Yandex Go'da manzil yozish: "Chil" deysiz, "Chilonzor" chiqadi.

Native variantlarni eslang:

  • select — faqat tanlash, yozish yo'q.
  • input + datalist — yozish va takliflar. Lekin ro'yxat ko'rinishini boshqarib bo'lmaydi va u har brauzerda boshqacha.
  • Customizable select — ko'rinish boshqariladi, lekin yozib qidirish yo'q.

Ro'yxatda narx, rasm ko'rsatish yoki serverdan qidirish kerak bo'lsa — ARIA combobox.

8.2 Tuzilma (ARIA 1.2)

Malika "osh" deb yozdi, ikkita taklif chiqdi, u ↓ ni ikki marta bosdi:

html
<label for="taom-qidir">Taom qidirish</label>
<input id="taom-qidir" type="text" role="combobox"
       aria-autocomplete="list" aria-expanded="true"
       aria-controls="taom-takliflar"
       aria-activedescendant="taklif-2">
<!-- [html-validate-disable-next prefer-native-element] -->
<ul id="taom-takliflar" role="listbox" aria-label="Taomlar">
  <li id="taklif-1" role="option"
      aria-selected="false">Osh — 35 000 so'm</li>
  <li id="taklif-2" role="option"
      aria-selected="true">Oshqovoq somsa — 7 000 so'm</li>
</ul>
<p role="status">2 ta taom topildi</p>
  • role="combobox" — to'g'ridan-to'g'ri input da. label — o'zgarmagan, oddiy label.
  • aria-autocomplete="list" — "yozganingizga qarab takliflar ro'yxati chiqadi". Boshqa qiymatlar: none (ro'yxat yozuvga bog'liq emas), inline (maydonning o'zida davomi yoziladi), both (ikkalasi).
  • aria-expanded — ro'yxat ochiqmi.
  • aria-controls — ro'yxatning id si.
  • aria-activedescendant — hozir belgilangan taklif. Fokus esa maydonda qoladi.
  • role="listbox" va role="option" — takliflar ro'yxati va uning bandlari. aria-selected="true" — belgilangan band.
  • role="status" — natijalar soni. Uni jonli hududlar darsidan bilasiz: ekran o'quvchi "2 ta taom topildi" deb o'zi aytadi.

Maslahat: Eski kodda boshqa tuzilmani uchratasiz: role="combobox" maydonni o'rab turgan div ga qo'yilgan. Bu — ARIA 1.1 dagi eski pattern. Yangi kodda rol maydonning o'zida bo'ladi.

8.3 Klaviatura

Tugma Nima bo'ladi
Harf yozish Maydonga yoziladi, ro'yxat yangilanadi
↓ / ↑ Keyingi / oldingi taklif (fokus maydonda qoladi)
Alt + ↓ Ro'yxatni ochadi, taklifni belgilamaydi
Enter Belgilangan taklif maydonga yoziladi, ro'yxat yopiladi
Esc Ro'yxatni yopadi; ikkinchi Esc — maydonni tozalaydi

8.4 html-validate nima deydi

Yuqoridagi koddagi <!-- [html-validate-disable-next ...] --> izohiga e'tibor bering. Usiz html-validate shunday yozadi:

text
  6:25  error  Prefer to use the native <select> element  prefer-native-element

Tarjimasi: "native select elementini ishlatgan ma'qul". Qoida to'g'ri gapiryapti — oddiy holatda select yaxshiroq. Bizda esa yozib qidirish kerak, select bunga yaramaydi. Bunday ongli istisnoda qoidani faqat keyingi qator uchun o'chirasiz va sababini izohda yozasiz. Butun loyihada o'chirib qo'yish esa xato bo'lardi.

Tekshirib ko'ring: Nega combobox'da roving tabindex emas, aria-activedescendant ishlatiladi?

Javob

Chunki foydalanuvchi takliflar bo'ylab yurib turib, yozishni ham davom ettiradi. Roving tabindex haqiqiy fokusni ro'yxat bandiga ko'chirardi — maydonga yozib bo'lmay qolardi. aria-activedescendant bilan fokus maydonda qoladi, ekran o'quvchi esa belgilangan taklifni o'qiydi.

9. Karusel va boshqa patternlar

Karusel — bir-birini almashtiradigan slaydlar ("Bugungi taklif", "Juma kuni osh"). U eng muammoli vidjetlardan biri:

  • avtomatik aylansa, 5 soniyadan uzoq harakat uchun to'xtatish tugmasi majburiy (WCAG talabi);
  • fokus yoki sichqoncha ustiga kelganda aylanish to'xtashi kerak;
  • ko'pchilik foydalanuvchi ikkinchi slaydgacha ham yetib bormaydi.

Tuzilma g'oyasi: umumiy konteynerda aria-roledescription="karusel" va aria-label. Har slaydda role="group", aria-roledescription="slayd" va aria-label="3 dan 1". aria-roledescription — rolning o'qiladigan nomini almashtiradi. Uni faqat shunday joylarda ishlating: boshqa hamma joyda u ekran o'quvchi uchun tanish rol nomini buzadi.

APG'da yana tooltip, slider, treeview, grid, toolbar, feed patternlari bor. Ularning hammasini yod olish shart emas. Qoida: yangi vidjet yasashdan oldin APG'dan uning sahifasini ochib o'qing.

10. Natijani tekshirish

Yozgan tuzilmangizni ikki usulda tekshiring:

  1. DevTools → Elements → Accessibility paneli. Tabni tanlang: Role — tab, Name — "Salatlar", holatlar orasida selected: false. Bu panelni Accessibility daraxti darsida o'rgangan edik.
  2. html-validate — no-missing-references qoidasi bilan. U aria-controls va aria-labelledby dagi mavjud bo'lmagan id larni topadi (sozlamasi pastda, xatolar bo'limida).

Haqiqiy ekran o'quvchi bilan tekshirish — Accessibility'ni tekshirish darsida.

11. Ko'p uchraydigan xatolar

11.1 Sayt navigatsiyasida role="menu"

Eng keng tarqalgan xato — yuqorida ko'rdik. Tuzatish: nav + ul + havolalar. Ochiladigan bo'lsa — disclosure (button aria-expanded).

11.2 Rol bor, klaviatura yo'q

role="tab" qo'yilgan, JavaScript esa faqat sichqoncha bosishini tinglaydi. Tuzatish: APG'ning Keyboard Interaction jadvalini to'liq bajaring. Bajara olmasangiz — rollarni ham qo'ymang, oddiy tugmalar qoldiring.

11.3 Holat yangilanmaydi

Panel almashdi, lekin aria-selected birinchi tabda "true" bo'lib qoldi. Ko'rgan odam farqni sezmaydi, ekran o'quvchi esa noto'g'ri tabni "tanlangan" deydi. Tuzatish: har o'zgarishda holat atributlari ham yangilanadi ("JavaScript nima qiladi" ro'yxati).

11.4 aria-controls mavjud bo'lmagan id ga

Nomda xato (panel-isiq) — aloqa uziladi. Tavsiya etilgan to'plam buni tekshirmaydi, shuning uchun .htmlvalidate.json ga qoidani qo'shing:

json
{
  "extends": ["html-validate:recommended"],
  "rules": {
    "no-missing-references": "error"
  }
}

Shunda xato aniq ko'rinadi:

text
  4:26  error  Element references missing id "panel-isiq"  no-missing-references

Tarjimasi: "element mavjud bo'lmagan panel-isiq id'siga murojaat qilyapti". 4:26 — 4-qator, 26-belgi: aynan aria-controls qiymati turgan joy.

11.5 Hamma tabda tabindex="0" yoki umuman button emas

div role="tab" + tabindex yo'q — klaviatura bilan tabga umuman yetib bo'lmaydi. Hammasida tabindex="0" — vidjet besh-oltita Tab to'xtashiga aylanadi. Tuzatish: button + roving tabindex.

12. Mashqlar

1-mashq (oson): Patternni tanlang

Har vaziyat uchun eng yaxshi yechimni yozing: native element (qaysi) yoki APG pattern (qaysi).

  1. Taom kartasida "Tarkibini ko'rsatish" tugmasi.
  2. Profil sahifasida "Ma'lumotlar / Buyurtmalar / Sozlamalar" yorliqlari, bittasi ko'rinadi, URL o'zgarmaydi.
  3. Sayt tepasidagi "Bosh sahifa, Menyu, Aloqa" havolalari.
  4. Buyurtma yonidagi ⋮ tugmasi: "Tahrirlash", "Nusxa olish", "O'chirish".
  5. Viloyatni tanlash — 14 ta variant, yozib qidirish shart emas.
Yechim
  1. Disclosure → details + summary.
  2. Tabs → tablist, tab, tabpanel (ARIA kerak).
  3. Navigatsiya → nav + ro'yxat + havolalar. Menyu emas!
  4. Menyu tugmasi → button aria-haspopup + role="menu" — bu haqiqiy amallar ro'yxati.
  5. select — native element yetarli.

Beshtadan faqat ikkitasida ARIA kerak bo'ldi. Real loyihalarda nisbat taxminan shunday.

2-mashq (o'rta): To'rtinchi tab

«Bahor» menyusiga "Shirinliklar" bo'limi qo'shildi. To'rtinchi tab va paneli uchun HTML yozing. Tab tanlanmagan. Tabning id si tab-shirin, panelniki panel-shirin. Panelda "Chak-chak — 15 000".

Ishora: tanlanmagan tabda ikki atribut bor — aria-selected="false" va tabindex ning qiymati . Panel esa hidden.

Yechim
html
<button type="button" role="tab" id="tab-shirin"
        aria-selected="false" tabindex="-1"
        aria-controls="panel-shirin">Shirinliklar</button>

Bu tugma tablist ichiga, oxirgi tabdan keyin qo'yiladi. Panel — boshqa panellar yoniga:

html
<div role="tabpanel" id="panel-shirin"
     aria-labelledby="tab-shirin" tabindex="0" hidden>
  <ul>
    <li>Chak-chak — 15 000</li>
  </ul>
</div>

Tab va panel bir-biriga ikki tomonlama bog'langan: tab aria-controls bilan panelni, panel aria-labelledby bilan tabni ko'rsatadi. Ekran o'quvchi endi "4 dan 4" deydi — sonni brauzer o'zi yangiladi.

3-mashq (qiyin): Buzilgan combobox

Stajyor filial tanlash maydonini yozdi. Unda beshta xato bor. Toping va tuzatilgan variantni yozing.

html
<div role="combobox">
  <input id="filial" type="text"
         aria-controls="filiallar">
</div>
<ul id="filial-royxat" role="menu">
  <li role="menuitem">Chilonzor</li>
  <li role="menuitem">Yunusobod</li>
</ul>

Eslatma: yorliq, role joyi, ro'yxat roli, aria-controls va holat atributiga qarang.

Yechim
  1. label yo'q — maydonning nomi yo'q.
  2. role="combobox" o'rab turgan div da — bu eski ARIA 1.1 usuli. Rol input ning o'zida bo'ladi.
  3. aria-controls="filiallar", ro'yxatning id si esa filial-royxat — aloqa uzilgan.
  4. Ro'yxat role="menu" — takliflar amallar emas. listbox va option bo'lishi kerak.
  5. aria-expanded yo'q — ekran o'quvchi ro'yxat ochiq-yopiqligini bilmaydi.
html
<label for="filial">Filial</label>
<input id="filial" type="text" role="combobox"
       aria-autocomplete="list" aria-expanded="false"
       aria-controls="filial-royxat">
<!-- [html-validate-disable-next prefer-native-element] -->
<ul id="filial-royxat" role="listbox" aria-label="Filiallar"
    hidden>
  <li id="filial-1" role="option"
      aria-selected="false">Chilonzor</li>
  <li id="filial-2" role="option"
      aria-selected="false">Yunusobod</li>
</ul>

Yana bir savol bering: filiallar faqat ikkita bo'lsa, combobox umuman kerakmi? Ikki variant uchun ikki radio tugma yoki select ancha sodda va ishonchli.

13. Real ishda

  • Headless kutubxonalar. Radix, React Aria, Headless UI kabi kutubxonalar APG patternlarini tayyor holda beradi: rollar, holatlar, klaviatura — hammasi ichida. Ularni UI kutubxonalar xaritasi va Radix Primitives darslarida ko'ramiz. Kutubxonani tanlashda birinchi savol: "APG'ga amal qiladimi?"
  • Testlar rol bo'yicha. React Testing Library elementni getByRole("tab", { name: "Salatlar" }) kabi topadi. To'g'ri rollar — ham accessibility, ham ishonchli testlar. Buni RTL darsida ko'rasiz.
  • Kod review. Tajribali dasturchi role="menu" ni ko'rsa, darhol "bu haqiqiy menyumi yoki navigatsiya?" deb so'raydi.
  • Intervyu. "Tabs'ni accessible qilib qanday yasaysiz?" — frontend intervyularida uchraydi. Yaxshi javob: rollar, aria-selected, roving tabindex, strelkalar, APG'ga havola.

Xulosa

  • APG — tabs, menyu, combobox kabi vidjetlar uchun rol, holat va klaviatura qoidalari yozilgan W3C qo'llanmasi.
  • Avval native element: details, details name, dialog, select, datalist. ARIA — faqat ular yetmaganda.
  • Vidjet — bitta Tab to'xtashi; ichida strelkalar. Usullari: roving tabindex yoki aria-activedescendant.
  • role="menu" — amallar uchun, sayt navigatsiyasi uchun emas.
  • ARIA faqat va'da beradi: holatlar (aria-selected, aria-expanded) va klaviaturani JavaScript bajaradi.

Keyingi dars: Kontent accessibility'si — kod emas, matnning o'zi: oddiy til, sarlavhalar, havola matni, rang va harakat.

Manbalar

  • W3C WAI: "ARIA Authoring Practices Guide (APG)" — Patterns, "Read Me First" — w3.org/WAI/ARIA/apg
  • W3C: "WAI-ARIA 1.2" — w3.org/TR/wai-aria-1.2
  • MDN: "ARIA: tab role", "ARIA: combobox role" — developer.mozilla.org
  • html-validate: "prefer-native-element", "no-missing-references" — html-validate.org
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
ARIA Authoring Practices (APG): tabs, akkordeon, menyu tugmasi va combobox — IlmHamroh