İçeriğe geç
academia.sh

Ders 01 / 25

Düğmeler

Düğme belirtiminin altı bölümü, yerel ögenin getirdiği davranışlar, basılı kalma durumunun bildirimi, klavye sözleşmesi ve tıklanabilir alanın hedef boyutu ölçütleriyle denetimi.

İçindekiler

Bileşen kataloğu kuruldu, adlandırma sözleşmesi yazıldı, sürümleme ve katkı süreci işliyor. Katalogdaki her kayıt bir ad, bir olgunluk düzeyi ve bir kullanım rehberi taşıyor. Ancak bir bileşenin katalogda bulunması, onun ne yaptığının yazılı olduğu anlamına gelmez: “birincil düğme” kaydı düğmenin nasıl göründüğünü söyler, klavyeden nasıl çalıştırıldığını, erişilebilirlik ağacında hangi adla ve hangi durumla göründüğünü söylemez.

Bu kurs o eksik yarıyı yazar. Her ders bir bileşeni belirtim olarak ele alır ve altı soruyu aynı sırayla yanıtlar. Kütüphane katalog arayüzü — arama alanı, süzgeç seçimleri, sonuç tablosu, kayıt ayrıntısı ve ödünç alma formu — bütün derslerin ortak örneğidir. İlk bileşen düğmedir, çünkü kalan bileşenlerin çoğu onu içerir.

Belirtimin Altı Bölümü

Bir bileşen belirtimi şu sırayla yazılır: bileşenin çözdüğü sorun ve ne zaman kullanılmayacağı; yerel karşılığın ne olduğu; rol, ad ve durumun nereden hesaplandığı; klavye sözleşmesi; ölçülebilir kısıtlar; sık yapılan hata ve nasıl saptandığı.

Sıra keyfi değildir. İlk iki bölüm yanıtlanmadan üçüncüsüne geçilirse, yerel bir öge yerine anlamsız bir kapsayıcı seçilmiş olur ve kalan dört bölüm o yanlışın üzerine yazılır. Frontend Kalitesi kursundaki birinci kural bu yüzden belirtimin de ikinci maddesidir: gereken anlamı taşıyan yerel bir öge varsa ARIA kullanılmaz.

Düğmenin İşi

Düğme, sayfada bir eylem başlatan denetimdir: aramayı çalıştırmak, süzgeçleri temizlemek, bir kaydı ödünç alma listesine eklemek, formu göndermek. Ortak özellikleri, çalıştırıldığında adres çubuğundaki adresin değişmemesidir.

Düğme kullanılmayacağı yer de aynı ölçütle belirlenir: kullanıcı başka bir kaynağa gidiyorsa bileşen düğme değil bağlantıdır. Katalogda bir kayda tıklamak kayıt ayrıntısı sayfasını açar; bu bir eylem değil, bir gezinmedir. Ayrımın tam kuralı ve ihlalinin nasıl saptandığı bu konunun son dersindedir.

Yerel Öge Önce

Karşılık button ögesidir ve type özniteliği üç değer alır. submit değeri ögeyi form gönderimine bağlar ve bir form içinde öznitelik yazılmadığında geçerli olan değerdir; button değeri hiçbir varsayılan eylem taşımaz, davranışı yalnızca bağlanan kod belirler; reset değeri alanları başlangıç değerlerine döndürür.

Bu ayrımın atlanması somut bir kırılma üretir: ödünç alma formunun içine konan “Süzgeci temizle” düğmesine type="button" yazılmadığında düğme formu gönderir. Kullanıcı bir alanı temizlemek isterken kaydı ödünç almış olur.

Yerel öge, rolün yanında beş şey daha getirir: odaklanabilirlik, giriş ve boşluk tuşlarıyla çalıştırılabilirlik, devre dışı durumunun ağaca bildirimi, form gönderimiyle ilişki ve gönderici olarak gönderim listesine kendi ad–değer çiftini eklemesi. Bunların hiçbiri div ögesine rol yazılarak gelmez.

Rol, Ad ve Durum

Rol örtük olarak button ögesinden gelir; ayrıca bildirilmez.

Ad, düğmenin içeriğinden hesaplanır. Metin taşıyan düğmelerde bu kendiliğinden çalışır. Yalnız simge taşıyan düğmelerde — sonuç tablosundaki işaretleme ve ödünç alma düğmelerinde — simgenin alternatif metni boşsa düğme adsız kalır. Katalog belirtiminde kural şudur: simge düğmelerinin adı, simgeye değil düğmeye yazılır; simge her koşulda sunumsaldır.

İki durum bildirimi düğmeye aittir. Birincisi devre dışı olmaktır: disabled özniteliği hem ağaca bildirir hem ögeyi odak dışına çıkarır. aria-disabled="true" yalnızca bildirir, öge odak alır ve tıklanabilir kalır; bu, kullanıcının düğmeyi bulup neden çalışmadığını okuyabilmesi istendiğinde seçilir ve tıklamanın kod tarafında yok sayılması gerekir.

İkincisi basılı kalma durumudur (aria-pressed): iki durumlu bir düğmenin açık mı kapalı mı olduğunu bildirir. Katalogda “Yalnız rafta olanlar” süzgeci böyle bir düğmedir. Bu durum, Arayüz Tasarımının Temelleri kursunda tanımlanan geçici basılı etkileşim durumundan ayrıdır: biri tuş bırakılınca biter, diğeri kullanıcı yeniden basana kadar sürer. Görsel tasarımın ikisini ayrı kanallarda kodlaması gerekir.

Klavye Sözleşmesi

Tuş Davranış
Tab Odağı düğmeye getirir; her düğme kendi başına bir sekme durağıdır.
Shift+Tab Önceki sekme durağına döner.
Enter Düğmeyi çalıştırır; tuşa basıldığı anda tetiklenir.
Boşluk Düğmeyi çalıştırır; tuş bırakıldığında tetiklenir.

İki tuşun tetiklenme anı arasındaki fark yerel ögede kendiliğinden vardır ve elle yazılan bir düğmede yeniden üretilmesi gerekir. Boşluk tuşunun bırakılışta tetiklenmesi, kullanıcıya tuşu basılı tutup düğmeden vazgeçme olanağı verir; giriş tuşunun basılışta tetiklenmesi ise form gönderiminin beklenen davranışıdır.

Odak, düğme çalıştırıldıktan sonra düğmede kalır. Düğme sayfadan kaldırılıyorsa — “Süzgeci temizle” düğmesi süzgeç kalmadığında gizleniyorsa — odağın nereye gideceği belirtilmek zorundadır; belirtilmezse odak belgenin köküne düşer.

Tıklanabilir Alan Ölçülür

Düğmenin görsel boyutu bir tasarım tercihi değil, ölçütlere bağlı bir kısıttır. 2.5.8 Hedef Boyutu (En Az) ölçütü her hedefin en az 24×24 CSS pikseli olmasını ister ve beş istisna tanır; bunların en çok işe yarayanı aralık istisnasıdır: küçük kalan bir hedefin merkezine yerleştirilen 24 piksel çaplı daire, başka bir hedefe ya da başka bir küçük hedefin dairesine değmiyorsa ölçüt karşılanır. 2.5.5 Hedef Boyutu (Gelişmiş) ölçütü aynı ölçüyü 44 piksele çıkarır.

// hedef.mjs — dugme hedef boyutunun 2.5.8 ve 2.5.5 olcutlerine gore denetimi

// Katalog arac cubugu ve sonuc tablosu satiri: CSS pikseli cinsinden kutular.
// x,y sol ust kose; w,h genislik ve yukseklik.
const ARAYUZ = [
  { ad: "button#ara",              x: 16,  y: 16, w: 88,  h: 44 },
  { ad: "button#suzgecleri-sil",   x: 112, y: 16, w: 140, h: 44 },
  { ad: "button#gorunum-liste",    x: 600, y: 26, w: 24,  h: 24 },
  { ad: "button#gorunum-izgara",   x: 628, y: 26, w: 24,  h: 24 },
  { ad: "a#kayit[K-118]",          x: 60,  y: 80, w: 220, h: 20 },
  { ad: "button#isaretle[K-118]",  x: 700, y: 80, w: 20,  h: 20 },
  { ad: "button#odunc[K-118]",     x: 720, y: 80, w: 20,  h: 20 },
];

const EN_KUCUK = 24;   // 2.5.8 Hedef Boyutu (En Az), AA
const GELISMIS = 44;   // 2.5.5 Hedef Boyutu (Gelismis), AAA

const merkez = (t) => [t.x + t.w / 2, t.y + t.h / 2];

// 24 px capli daire ile bir kutunun kesisip kesismedigi
function daireKutuKesisir(t, k) {
  const [cx, cy] = merkez(t);
  const yx = Math.max(k.x, Math.min(cx, k.x + k.w));
  const yy = Math.max(k.y, Math.min(cy, k.y + k.h));
  return Math.hypot(cx - yx, cy - yy) < EN_KUCUK / 2;
}

// Iki 24 px capli dairenin kesismesi: merkezler arasi uzaklik < 24
function daireDaireKesisir(a, b) {
  const [ax, ay] = merkez(a);
  const [bx, by] = merkez(b);
  return Math.hypot(ax - bx, ay - by) < EN_KUCUK;
}

const kucuk = (t) => Math.min(t.w, t.h) < EN_KUCUK;

// Aralik istisnasi: kucuk hedefin dairesi baska bir hedefe ya da
// baska bir kucuk hedefin dairesine degmemeli.
function aralikIstisnasi(t, hepsi) {
  const carpisan = [];
  for (const b of hepsi) {
    if (b === t) continue;
    const carpti = kucuk(b) ? daireDaireKesisir(t, b) : daireKutuKesisir(t, b);
    if (carpti) carpisan.push(b.ad);
  }
  return carpisan;
}

function denetle(baslik, arayuz) {
  console.log(baslik);
  console.log("hedef                    olcu     en kucuk kenar  2.5.8   2.5.5   aralik istisnasi");
  for (const t of arayuz) {
    const kenar = Math.min(t.w, t.h);
    const carpisan = kucuk(t) ? aralikIstisnasi(t, arayuz) : [];
    const gecer258 = !kucuk(t) || carpisan.length === 0;
    const gecer255 = Math.min(t.w, t.h) >= GELISMIS;
    const not = !kucuk(t)
      ? "gerekmiyor"
      : carpisan.length === 0
        ? "uygulandi"
        : "carpisan: " + carpisan.join(", ");
    console.log(
      t.ad.padEnd(24) +
        `${t.w}x${t.h}`.padEnd(9) +
        String(kenar).padStart(14) +
        (gecer258 ? "  gecti" : "  KALDI").padEnd(8) +
        (gecer255 ? "  gecti" : "  KALDI").padEnd(8) +
        "  " + not,
    );
  }
  const kalan = arayuz.filter((t) => kucuk(t) && aralikIstisnasi(t, arayuz).length > 0);
  console.log(`2.5.8 ihlali: ${kalan.length} hedef`);
}

denetle("mevcut arac cubugu ve satir denetimleri:", ARAYUZ);

// Duzeltme: satir ici denetimler 24x24'e cikarilir ve aralari 8 px acilir.
const DUZELTILMIS = ARAYUZ.map((t) => {
  if (t.ad === "button#isaretle[K-118]") return { ...t, w: 24, h: 24, x: 696, y: 78 };
  if (t.ad === "button#odunc[K-118]") return { ...t, w: 24, h: 24, x: 728, y: 78 };
  return t;
});

console.log("");
denetle("satir ici denetimler 24x24, aralik 8 px:", DUZELTILMIS);

// Hedefi buyutmeden cozmek: kutu ayni kalir, aralik acilir.
const YALNIZ_ARALIK = ARAYUZ.map((t) =>
  t.ad === "button#odunc[K-118]" ? { ...t, x: 726 } : t,
);

console.log("");
denetle("kutular 20x20 kaldi, yalniz aralik 6 px acildi:", YALNIZ_ARALIK);
mevcut arac cubugu ve satir denetimleri:
hedef                    olcu     en kucuk kenar  2.5.8   2.5.5   aralik istisnasi
button#ara              88x44                44  gecti   gecti   gerekmiyor
button#suzgecleri-sil   140x44               44  gecti   gecti   gerekmiyor
button#gorunum-liste    24x24                24  gecti   KALDI   gerekmiyor
button#gorunum-izgara   24x24                24  gecti   KALDI   gerekmiyor
a#kayit[K-118]          220x20               20  gecti   KALDI   uygulandi
button#isaretle[K-118]  20x20                20  KALDI   KALDI   carpisan: button#odunc[K-118]
button#odunc[K-118]     20x20                20  KALDI   KALDI   carpisan: button#isaretle[K-118]
2.5.8 ihlali: 2 hedef

satir ici denetimler 24x24, aralik 8 px:
hedef                    olcu     en kucuk kenar  2.5.8   2.5.5   aralik istisnasi
button#ara              88x44                44  gecti   gecti   gerekmiyor
button#suzgecleri-sil   140x44               44  gecti   gecti   gerekmiyor
button#gorunum-liste    24x24                24  gecti   KALDI   gerekmiyor
button#gorunum-izgara   24x24                24  gecti   KALDI   gerekmiyor
a#kayit[K-118]          220x20               20  gecti   KALDI   uygulandi
button#isaretle[K-118]  24x24                24  gecti   KALDI   gerekmiyor
button#odunc[K-118]     24x24                24  gecti   KALDI   gerekmiyor
2.5.8 ihlali: 0 hedef

kutular 20x20 kaldi, yalniz aralik 6 px acildi:
hedef                    olcu     en kucuk kenar  2.5.8   2.5.5   aralik istisnasi
button#ara              88x44                44  gecti   gecti   gerekmiyor
button#suzgecleri-sil   140x44               44  gecti   gecti   gerekmiyor
button#gorunum-liste    24x24                24  gecti   KALDI   gerekmiyor
button#gorunum-izgara   24x24                24  gecti   KALDI   gerekmiyor
a#kayit[K-118]          220x20               20  gecti   KALDI   uygulandi
button#isaretle[K-118]  20x20                20  gecti   KALDI   uygulandi
button#odunc[K-118]     20x20                20  gecti   KALDI   uygulandi
2.5.8 ihlali: 0 hedef

Üç koşum üç ayrı bilgi veriyor.

Birinci koşumda araç çubuğu ölçütü karşılıyor, sonuç tablosunun satır içi denetimleri karşılamıyor. İki düğmenin merkezleri arasındaki uzaklık 20 piksel; iki dairenin kesişmemesi için gereken 24. Kayıt bağlantısı da 20 piksel yüksekliğinde ama aralık istisnasını sağlıyor, çünkü çevresinde başka hedef yok.

İkinci koşum, doğrudan çözümü uyguluyor: kutular 24×24’e çıkarıldığında istisnaya hiç gerek kalmıyor. Üçüncü koşum ise ölçütün yanlış okunmasını düzeltiyor — kutuların büyütülmesi zorunlu değildir. Yalnızca aralığın 6 piksele çıkarılması, merkezleri 26 piksele taşıyarak ölçütü karşılatıyor. Yoğun bir sonuç tablosunda satır yüksekliğini korumak gerektiğinde kullanılabilecek yol budur.

2.5.5 sütunu bütün simge düğmelerinde “KALDI” gösteriyor. Bu bir ihlal değil: 44 piksel ölçüsü AAA düzeyindedir. Sütunun belirtimde bulunması, dokunmatik kullanım hedefleniyorsa hangi düğmelerin büyütülmesi gerektiğini önceden gösterir.

Hiyerarşi Davranış Farkı Değildir

Katalog araç çubuğunda üç görsel ağırlık kullanılır: dolgulu birincil düğme (“Ara”), çerçeveli ikincil düğme (“Süzgeçleri temizle”) ve dolgusuz düz düğme (görünüm değiştiriciler). Bu ayrım tümüyle görseldir; üçünün rolü, adı, klavye sözleşmesi ve hedef boyutu ölçütü aynıdır.

Belirtimde yazılması gereken tek kural, bir görünümde en çok bir birincil düğme bulunmasıdır. İki birincil düğme, görsel hiyerarşinin taşıdığı “önerilen eylem budur” bilgisini siler. Bu kural bir uygunluk ölçütünden gelmez; Arayüz Tasarımının Temelleri kursundaki karşıtlık ve vurgu kararının bileşen düzeyindeki karşılığıdır.

Sık Yapılan Hata

En sık üretilen üç kusur ve saptama yolları şunlardır.

Adsız simge düğmesi. Alternatif metni boş bir simge taşıyan düğme ağaçta adsız görünür. Saptaması araçsızdır: sayfadaki her düğmenin erişilebilir adı listelenir, boş olan aranır. Otomatik denetleyicilerin varlık kuralı bunu yakalar.

Görünen metinle adın ayrışması. Düğmenin üzerinde “Ödünç al” yazarken aria-label bildirimi “Ekle” diyorsa, sesle arayüz kullanan kişinin söylediği ad hiçbir ögeye uymaz; 2.5.3 Ad Etikette ölçütü bunu yasaklar. Saptaması, görünen metnin erişilebilir adın içinde geçip geçmediğinin denetlenmesidir.

Devre dışı düğmenin gerekçesiz kalması. Rafta olmayan bir kayıt için ödünç alma düğmesi disabled yazılarak kapatıldığında düğme odak dışına çıkar ve kullanıcı nedeni okuyamaz. Saptaması bir klavye turudur: sekme tuşuyla gezilen sayfada bulunamayan ama ekranda görünen her denetim bu durumdadır. Belirtimin kararı, nedenin okunması gerekiyorsa düğmenin aria-disabled ile bildirilmesi ve nedenin aria-describedby ile bağlanmasıdır.

Özet

  • Bileşen belirtimi altı bölümden oluşur: sorun ve kullanılmayacağı yer, yerel karşılık, rol–ad–durum, klavye sözleşmesi, ölçülebilir kısıtlar, sık yapılan hata ve saptaması.
  • Düğme eylem başlatır; adres değişiyorsa bileşen düğme değildir. type özniteliği yazılmadığında form içindeki düğme gönderim düğmesi olur.
  • Ad düğme içeriğinden hesaplanır; simge düğmelerinde ad düğmeye yazılır. disabled ögeyi odak dışına çıkarır, aria-disabled yalnızca bildirir ve odakta bırakır.
  • Giriş tuşu basılışta, boşluk tuşu bırakılışta tetikler; elle yazılan bir düğmede bu fark yeniden üretilmelidir.
  • 2.5.8 her hedeften 24×24 CSS pikseli ister; aralık istisnası, kutuyu büyütmeden merkezler arası uzaklığı 24 pikselin üstüne çıkararak da karşılanabilir.
  • Birincil, ikincil ve düz düğme ayrımı yalnızca görseldir; bir görünümde en çok bir birincil düğme bulunur.

Sonraki Adım

Düğme, kullanıcıdan hiçbir şey almadan çalışan bir denetimdir: adı sabittir, değeri yoktur ve tek bildirdiği şey basılıp basılmadığıdır. Katalog arayüzünün asıl veri toplayan bileşeni ise arama alanıdır ve orada ad tek başına yetmez — alanın bir etiketi, bir biçim ipucu, bir yardım metni ve gerektiğinde bir hata iletisi vardır. Bunların dördü de ekranda alanın çevresinde durur, ancak erişilebilirlik ağacında birbirinden ayrı bildirimlerdir ve duyurulma sıraları farklıdır. Sonraki ders metin girdisini bu dört metnin düzeni üzerinden belirtir.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat