ARIA (Accessible Rich Internet Applications), HTML öğelerine eklenen role ve aria-* öznitelikleriyle ekran okuyucu gibi yardımcı teknolojilere "bu öğe nedir, şu an hangi durumdadır, neyle ilişkilidir" bilgisini veren bir rol ve öznitelik kümesidir. Kısa cevap şudur: yerel bir HTML öğesi (<button>, <nav>, <progress>, <details> gibi) işinizi görüyorsa ARIA eklemeyin; yalnızca HTML'in karşılığını vermediği özel bileşenlerde ve dinamik durumlarda ARIA kullanın.

Bu yazıda ARIA'nın neyi değiştirip neyi değiştirmediğini, "ARIA'nın ilk kuralı"nı, altı rol kategorisini, durum ile özellik arasındaki farkı, aria-expanded, aria-pressed ve aria-hidden gibi sık kullanılan öznitelikleri çalışan örneklerle ele alıyoruz. Erişilebilir ad konusu (aria-label, aria-labelledby, aria-describedby) ayrı bir yazıda: erişilebilir ad rehberi. Serinin tamamı için HTML öğrenme rehberine bakabilirsiniz.

ARIA ne yapar, ne yapmaz?

Tarayıcı her sayfa için DOM'un yanında bir de erişilebilirlik ağacı oluşturur. Ekran okuyucular sayfayı bu ağaç üzerinden okur: her düğümün bir rolü (düğme, bağlantı, başlık), bir adı ("Kaydet") ve varsa durumu (basılı, açık, seçili) vardır. ARIA öznitelikleri yalnızca bu ağaçtaki bilgiyi değiştirir. MDN bunu açıkça vurgular: ARIA bir öğenin işlevini veya davranışını değiştirmez. role="button" yazdığınız bir <div> düğme gibi duyurulur ama klavyeyle odaklanmaz, Enter veya Boşluk tuşuyla tetiklenmez, form göndermez.

MDN'nin ARIA giriş sayfasındaki örnek bu farkı iyi gösterir. Anlamsız bir <div> öğesine role="progressbar", aria-valuemin, aria-valuemax ve aria-valuenow ekleyerek bir ilerleme çubuğu tarif edebilirsiniz. Ancak aria-valuenow değerini JavaScript ile sürekli güncellemek ve öğeyi CSS ile ilerleme çubuğu gibi göstermek sizin işinizdir. Aynı sonuç yerel öğeyle tek satırda elde edilir:

html
<!-- ARIA ile tarif edilen ilerleme cubugu: deger ve gorunum sizin sorumlulugunuzda -->
<div id="yukleme" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"></div>

<!-- Yerel oge: rol ve deger tarayicidan gelir -->
<progress id="yukleme2" value="75" max="100">%75</progress>

MDN ayrıca <progress> öğesinde min özniteliğine izin verilmediğini, en küçük değerin her zaman 0 olduğunu not eder. <progress> ve <meter> öğelerinin ayrıntıları için progress, meter ve output yazısına bakın.

ARIA'nın ilk kuralı: önce yerel HTML

W3C'nin "Using ARIA" notundaki ilk kural, MDN'nin de alıntıladığı haliyle şöyle özetlenebilir: ihtiyaç duyduğunuz anlam ve davranışı zaten taşıyan bir HTML öğesi veya özniteliği varsa, başka bir öğeyi ARIA rolüyle kılık değiştirmek yerine o yerel öğeyi kullanın. Gerekçe basittir: yerel öğeler klavye erişimini, rolü ve durumu kendiliğinden getirir. ARIA seçtiğinizde ise tarayıcının yaptığı her şeyi betikle taklit etme sorumluluğu size geçer.

MDN bu kurala "kötü ARIA, hiç ARIA olmamasından kötüdür" sözünü de ekler ve WebAIM'in bir milyondan fazla ana sayfa üzerinde yaptığı taramaya atıf yapar: ARIA kullanılan ana sayfalarda, kullanılmayanlara göre ortalama yüzde 41 daha fazla hata tespit edilmiş. Bu, ARIA'nın zararlı olduğu anlamına gelmez; yanlış yerde kullanıldığında erişilebilirliği iyileştirmek yerine bozabileceğini gösterir.

Aşağıdaki iki düğme ekran okuyucuya aynı rolü bildirir, ama yalnızca ikincisi gerçek bir düğme gibi davranır:

html
<!-- Kotu: rol var, davranis yok. tabindex, click ve keydown isleyicileri elle eklenmeli -->
<div id="kaydet-div" role="button" tabindex="0">Kaydet</div>

<!-- Iyi: odaklanma, Enter ve Bosluk ile tetiklenme tarayicidan gelir -->
<button type="button" id="kaydet">Kaydet</button>

MDN'nin button rolü sayfasına göre role="button" kullanırsanız öğeyi odaklanabilir yapmanız, click ve keydown olayları için işleyici yazmanız ve hem Enter hem de Boşluk tuşunu işlemeniz gerekir. Yerel <button> öğesinde click olayı fare tıklamasında da, odaktayken Boşluk veya Enter basıldığında da tetiklenir; <div> ya da <span> ile yapılan düğmede ise role="button" olsa bile yalnızca fare tıklamasında tetiklenir. Düğme türleri ve form davranışı için button etiketi yazısına göz atın.

ARIA rolleri: altı kategori

ARIA rolleri: altı kategori: Belge yapısı, Bileşen (widget), Bileşik bileşen, Yer işareti

Rol, role="rol-adi" biçiminde eklenir ve öğenin ne tür bir arayüz parçası olduğunu söyler. HTML'deki birçok öğenin varsayılan bir rolü vardır; örneğin <input type="radio"> öğesinin rolü radiodur. Anlamsız <div> ve <span> öğelerinin ise ek bir anlam verilmedikçe rolü yoktur. MDN rolleri altı kategoride toplar:

KategoriÖrnek rollerNot
Belge yapısıtoolbar, tooltip, feed, math, presentation/none, noteÇoğunun HTML karşılığı var (article, img, list, table, heading); onları kullanın
Bileşen (widget)scrollbar, searchbox, slider, spinbutton, switch, tab, tabpanel, treeitemGenellikle JavaScript ile etkileşim gerektirir
Bileşik bileşencombobox, menu, menubar, tablist, tree, treegridAlt rollerle birlikte kullanılır
Yer işaretibanner, complementary, contentinfo, form, main, navigation, region, searchheader, aside, footer, form, main, nav, section, search öğelerinin örtük rolleri
Canlı bölgealert, log, marquee, status, timerDinamik değişiklikleri duyurur
Pencerealertdialog, dialogSayfa içindeki alt pencereler
Soyutcommand, composite, input, landmark, range, widget, window...Yalnızca tarayıcılar içindir, içerikte kullanılmaz

Tablo yedi satır gösteriyor çünkü MDN bileşik bileşenleri bileşen kategorisinin alt başlığı olarak verir. Soyut roller için WAI-ARIA belirtimi kesindir: içerik yazarları soyut rolleri kullanmamalıdır; kullansanız da yardımcı teknolojilere anlamlı bir bilgi geçmez. Yer işareti rollerinde ise MDN ölçülü olmayı önerir: çok sayıda yer işareti ekran okuyucuda "gürültü" yaratır ve sayfanın genel düzenini anlamayı zorlaştırır.

Bazı rollerin kendine özgü kuralları vardır. Bazıları belirli durum veya özelliklerle birlikte kullanılmak zorundadır, bazıları da yalnızca başka bir rolün içinde anlam taşır. MDN'nin uyarıcı örneği şudur: <ul role="tabpanel"> ekran okuyucuda "sekme paneli" olarak duyurulur; ama içinde gerçek sekmeler yoksa öğe aslında bir sekme paneli değildir ve erişilebilirlik iyileşmek yerine kötüleşir.

Durumlar ve özellikler: aria-* öznitelikleri

ARIA öznitelikleri iki gruba ayrılır. Özellikler (properties) bir bileşenin görece sabit niteliklerini anlatır: bir açılır menüsü olup olmadığı (aria-haspopup), zorunlu olup olmadığı (aria-required) veya hangi öğe tarafından etiketlendiği (aria-labelledby) gibi. Durumlar (states) ise etkileşim sırasında değişen bilgilerdir: işaretli mi (aria-checked), devre dışı mı (aria-disabled), açık mı (aria-expanded), basılı mı (aria-pressed). Durumlar değiştikçe değerlerini betikle güncellemek zorundasınız; aksi halde ekran okuyucu eski bilgiyi okur.

MDN ARIA özniteliklerini dört kategoride listeler: bileşen öznitelikleri (aria-checked, aria-disabled, aria-expanded, aria-invalid, aria-valuenow gibi), canlı bölge öznitelikleri (aria-live, aria-atomic, aria-relevant, aria-busy), sürükle bırak öznitelikleri (aria-dropeffect, aria-grabbed) ve ilişki öznitelikleri (aria-controls, aria-describedby, aria-labelledby, aria-owns, aria-activedescendant gibi).

Bunların bir kısmı "global" özniteliktir; yani rol verilmiş olsun ya da olmasın her HTML öğesinde kullanılabilir. aria-describedby, aria-hidden, aria-live, aria-label ve aria-labelledby bu gruptadır. Tek istisna: aria-label ve aria-labelledby, presentation rolüne ve onun eş anlamlısı none rolüne sahip öğelerde kullanılamaz. Canlı bölgeler ve aria-live için WCAG temelleri yazısındaki bölüme bakın.

Uygulamalı örnek: aria-expanded ile aç-kapa düğmesi

Bir düğme başka bir içeriği gösterip gizliyorsa, MDN'ye göre düğmeye aria-controls ile kontrol edilen öğenin id değerini, aria-expanded ile de o anki durumu yazmalısınız. Aşağıdaki örnek MDN'nin kullanıcı adı yardım örneğinden uyarlandı. Görünür bir metni olmayan "?" düğmesine aria-label ile ad veriliyor, simge karakteri aria-hidden="true" ile erişilebilir addan çıkarılıyor ve açıklama paragrafı başlangıçta hidden ile gizleniyor:

html
<label for="kullanici">Kullanıcı adı</label>
<input id="kullanici" name="kullanici" aria-describedby="kullanici-aciklama" />
<button type="button" aria-expanded="false" aria-controls="kullanici-aciklama" aria-label="Kullanıcı adı hakkında yardım">
  <span aria-hidden="true">?</span>
</button>
<p id="kullanici-aciklama" hidden>
  Kullanıcı adı, bu hizmete giriş yaparken kullandığınız addır.
</p>

Düğmeye basıldığında hem paragrafın hidden özniteliğini kaldırmanız hem de aria-expanded değerini true yapmanız gerekir. ARIA bunu sizin yerinize yapmaz:

javascript
const dugme = document.querySelector("[aria-controls='kullanici-aciklama']");
const aciklama = document.getElementById("kullanici-aciklama");

dugme.addEventListener("click", () => {
  const acik = dugme.getAttribute("aria-expanded") === "true";
  dugme.setAttribute("aria-expanded", String(!acik));
  aciklama.hidden = acik;
});

MDN'nin bir uyarısını da not edin: aria-expanded özniteliğinin varlığı, öğenin başka bir şeyi kontrol ettiğini bildirir. Hiçbir şeyi açıp kapatmayan öğelere bu özniteliği eklemeyin. Ağaç görünümündeki uç düğümler için de aynı kural geçerlidir; alt düğümü olmayan bir treeitem öğesine aria-expanded verirseniz yardımcı teknoloji onu yanlışlıkla üst düğüm sanır. Betik gerektirmeyen bir aç-kapa için details ve summary öğeleri çoğu zaman daha iyi bir başlangıçtır. JavaScript tarafını öğrenmek isterseniz JavaScript öğrenme rehberi yardımcı olur.

Geçiş düğmesi: aria-pressed

aria-pressed, bir düğmeyi iki konumlu bir geçiş düğmesine (toggle button) dönüştürür. Değer false ise düğme basılı değildir, true ise basılıdır, mixed ise kısmen basılıdır (örneğin kontrol ettiği diğer düğmeler farklı durumdaysa). Öznitelik hiç yoksa düğme geçiş düğmesi değildir. Yerel <button> öğesine role eklemeden doğrudan aria-pressed yazabilirsiniz:

html
<button type="button" aria-pressed="false">Sesi kapat</button>

MDN burada önemli bir tasarım kuralı verir: geçiş düğmesinin etiketi durum değiştiğinde değişmemelidir. Etiket "Sesi kapat" olarak kalır, ekran okuyucu durumu ayrıca "basılı" ya da "basılı değil" diye bildirir. Tasarımınız etiketin "Sesi kapat" ile "Sesi aç" arasında değişmesini istiyorsa bu bir geçiş düğmesi değildir ve aria-pressed kullanılmamalıdır; aksi halde kullanıcı "Sesi aç, basılı" gibi çelişkili bir duyuru duyar.

aria-hidden ile role="presentation" aynı şey değildir

aria-hidden ile role="presentation" aynı şey değildir: aria-hidden="true" odaklanabilir bir öğeye ya da odaklanabilir öğe içeren bir..., Bir üst öğede aria-hidden="true" varsa alt...

aria-hidden="true", öğeyi ve tüm alt öğelerini erişilebilirlik ağacından çıkarır, ama ekrandan gizlemez. Süs amaçlı simgeler, tekrar eden metinler veya ekran dışındaki kapalı menüler için uygundur. role="presentation" (ya da role="none") ise yalnızca öğenin anlamını kaldırır; içerik yardımcı teknolojilere açık kalmaya devam eder. MDN'deki örnekte <h2 role="presentation"> yazmak başlığı bir <div> ile eşdeğer hale getirir; metin okunur ama başlık olarak duyurulmaz.

html
<!-- Simge erisilebilir addan cikarilir, dugmenin adi gorunur metinden gelir -->
<button type="button">
  <span class="simge" aria-hidden="true">&#9733;</span>
  <span>Favorilere ekle</span>
</button>

<!-- Liste anlami kaldirilir, icindeki baglantilar yine baglanti olarak kalir -->
<ul role="presentation">
  <li><a href="#bir">Birinci</a></li>
  <li><a href="#iki">İkinci</a></li>
</ul>

İkinci örnekte <ul> öğesinin anlamı kalkınca, bir listenin içinde olmak zorunda olan <li> öğeleri de bu rolü miras alır; ama <a> öğeleri bağlantı olarak duyurulmaya devam eder. MDN'ye göre tarayıcılar odaklanabilir öğelerdeki (bağlantılar, form alanları, tabindex verilmiş öğeler) ve global ARIA özniteliği taşıyan öğelerdeki presentation/none rolünü yok sayar.

  • aria-hidden="true" odaklanabilir bir öğeye ya da odaklanabilir öğe içeren bir kapsayıcıya eklenmemelidir; öğe klavyeyle odak alır ama ekran okuyucu onu göremez.
  • Bir üst öğede aria-hidden="true" varsa alt öğeye aria-hidden="false" yazmak onu yeniden görünür kılmaz.
  • HTML hidden özniteliği, CSS display: none veya visibility: hidden ile gizlenmiş öğelere aria-hidden eklemek gereksizdir; bunlar zaten ağaçtan çıkmıştır. Ayrıntılar için hidden ve inert yazısına bakın.
  • Görünür içeriği yardımcı teknolojilerden gizlemeden önce düşünün: MDN, bunu yalnızca aynı anlam ve işlev başka bir yolla sunuluyorsa önerir. Yardımcı teknoloji kullananların hepsi görme engelli değildir.

Rol, içeriği ve öğenin ömrünü de etkiler

Bazı roller alt öğelerin anlamını siler. MDN'nin button rolü sayfasına göre erişilebilirlik API'leri bir düğmenin içinde anlamlı öğeleri temsil edemez; bu yüzden tarayıcılar button rolündeki bir öğenin bütün alt öğelerine otomatik olarak presentation rolü uygular. <div role="button"><h3>Başlık</h3></div> yazdığınızda ekran okuyucu kullanıcısı için o başlık yoktur; erişilebilirlik ağacında yalnızca "Başlık" metnini taşıyan bir düğme kalır.

İkinci kural rolün değişmemesidir. MDN'nin bileşen rehberi, yerinde düzenleme (inline edit) örneğini verir: "görüntüleme" modunda salt okunur bir <input> öğesine button rolü verip "düzenleme" moduna geçince rolü kaldırmak cazip görünebilir. Bunu yapmayın. Rol değişecekse öğeyi kaldırıp yeni rolü taşıyan başka bir öğeyle değiştirin: görüntüleme modu için button rolü verilmiş bir öğe, düzenleme modu için ayrı bir metin <input> öğesi.

Klavye: rol vermek yetmez

MDN'nin bileşen rehberine göre ARIA ile yapılmış bir bileşende klavye davranışı şöyle olmalıdır: Tab tuşu bileşenin bütününe odak vermeli (bir menü çubuğuna Tab ile gelince odak ilk menü öğesine atlamamalı), ok tuşları bileşenin içinde gezinmeyi sağlamalı, form dışındaki bir bileşende Enter ve Boşluk denetimi etkinleştirmeli, bir formun içinde ise Boşluk denetimi etkinleştirirken Enter formun varsayılan eylemini göndermelidir. Emin olmadığınızda masaüstündeki eşdeğer denetimin davranışını taklit edin. Odak sırası ve tabindex değerleri için tabindex ve klavye erişimi yazısını okuyun.

Sık yapılan ARIA hataları

Sık yapılan ARIA hataları: Yerel öğe varken rol kullanmak, Örtük rolü tekrar etmek, Durumu güncellememek, Soyut rolleri kullanmak
  • Yerel öğe varken rol kullanmak: <button> yerine div role="button", <a> yerine span role="link", <h2> yerine div role="heading" gibi. MDN bu rollerin çoğu için "kullanmaktan kaçının" der.
  • Örtük rolü tekrar etmek: <nav role="navigation"> veya <main role="main"> yazmak bir şey kazandırmaz.
  • Durumu güncellememek: aria-expanded="false" ile başlayıp içerik açıldığında değeri true yapmamak.
  • Soyut rolleri kullanmak: role="widget", role="input" veya role="landmark" içerikte geçersizdir.
  • Odaklanabilir öğeyi aria-hidden="true" ile gizlemek.
  • Bir rolün gerektirdiği yapıyı kurmamak: içinde tab rolleri olmayan bir tablist, option içermeyen bir listbox gibi.
  • Bağlantıya role="button" verip yalnızca Enter'ı işlemek: MDN, düğmelerin Boşluk tuşuyla da tetiklenmesinin beklendiğini, bu yüzden Boşluk için de bir işleyici gerektiğini hatırlatır.

ARIA'yı gerçek yardımcı teknolojiyle test edin

MDN'ye göre ARIA desteği işletim sistemine, tarayıcıya, yardımcı teknolojinin türüne ve bunların sürümlerine göre değişir; eski yazılımlar bazı rolleri hiç desteklemeyebilir veya yanlış bildirebilir. Yardımcı teknoloji kullanan bazı kişiler, alıştıkları düzeni kaybetme kaygısıyla yazılımlarını güncellemekte isteksiz olabilir. Bu da yine semantik HTML'i öne çıkarır, çünkü yerel öğelerin desteği çok daha geniştir. Yazdığınız ARIA'yı gerçek bir ekran okuyucuyla deneyin; MDN tarayıcı emülatörlerinin ve simülatörlerin tam desteği ölçmek için yeterli olmadığını belirtir. Genel erişilebilirlik ilkeleri için WCAG temelleri yazısı iyi bir sonraki adımdır.

Sık Sorulan Sorular

ARIA eklemek sayfayı otomatik olarak erişilebilir yapar mı?

Hayır. ARIA yalnızca erişilebilirlik ağacındaki bilgiyi değiştirir; odaklanma, klavye ile tetikleme ve durum güncellemesi gibi davranışları sizin eklemeniz gerekir. Yanlış kullanılan ARIA, hiç kullanılmamasından daha çok sorun çıkarabilir.

Hangi durumlarda ARIA gerçekten gerekir?

HTML'de karşılığı olmayan bileşenlerde (sekme listesi, ağaç görünümü, araç çubuğu, birleşik kutu gibi), yerel öğelerin taşımadığı durum bilgisinde (bir düğmenin açtığı içeriğin açık olup olmadığı) ve dinamik güncellemelerin duyurulmasında (canlı bölgeler) ARIA gerekir.

role="presentation" ile aria-hidden="true" arasındaki fark nedir?

role="presentation" öğenin anlamını kaldırır ama içeriğini ekran okuyucuya açık bırakır. aria-hidden="true" öğeyi içeriğiyle birlikte erişilebilirlik ağacından tamamen çıkarır.

<code>&lt;button&gt;</code> öğesine role="button" yazmalı mıyım?

Gerek yoktur. <button> öğesinin örtük rolü zaten buttondur. Aynı şey <nav>, <main>, <ul> ve diğer anlamlı öğeler için de geçerlidir.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: HTML öğrenme rehberi · aria-label, aria-labelledby, aria-describedby · WCAG temelleri · semantik etiketler · tabindex ve klavye erişimi · hidden ve inert