İçeriğe geç
academia.sh

Ders 15 / 25

Araç İpuçları

Araç ipucunun belirtimi; ipucu ile açıklama baloncuğu ayrımı, 1.4.13 ölçütünün üç koşulunun kural denetimi, işaretçinin ipucuna ulaşmasının geometriyle hesaplanması ve dokunma erişiminin çözümü.

İçindekiler

Kip pencere odağı isteyerek devraldı; kullanıcı onu bir düğmeye basarak açtı ve kaçış tuşuyla kapattı. Araç ipucu tam tersi bir bileşendir: kullanıcı istemeden belirir, odağı almaz, kısa sürer ve çoğu kurulumda yalnız işaretçiyle çalışır.

Bu kendiliğindenlik onu en çok yanlış kurulan bileşen yapar. Fareyle çalışan bir kurulum klavyeyle hiç açılmaz; dokunmatik ekranda üzerine gelme diye bir durum olmadığı için ipucu hiç görünmez; kendiliğinden kaybolan bir katmanın içindeki metin okunmadan gider. Bu ders ipucunu üç koşula bağlar ve koşullardan birini geometriyle hesaplar.

Ne Çözer, Ne Zaman Kullanılmaz

Araç ipucu (tooltip), adı zaten olan bir denetime ek açıklama getiren katmandır. Katalog arayüzünde ödünç alma satırındaki “iade tarihi” başlığının yanındaki simge düğme buna örnektir: başlık kendi başına anlaşılır, ipucu tarihin nasıl hesaplandığını ekler.

İki kural bu tanımdan çıkar. Birincisi, ipucundaki bilgi hiçbir zaman zorunlu değildir; onsuz da görev tamamlanabilmelidir. İkincisi, ipucu denetimin adı olamaz; adı yalnız ipucunda bulunan bir düğme, ipucu görünmediğinde adsızdır.

Kullanılmayacak durumlar:

  • Etkileşimli içerik. İçinde bağlantı, düğme ya da girdi olan bir katman ipucu değildir; o katmana odak gitmesi gerekir ve gittiği anda ipucunun sözleşmesi bozulur.
  • Uzun metin. Birkaç cümlelik açıklama, alanın yanında duran kalıcı bir yardım metnine aittir; kaybolabilen bir katmanda okunamaz.
  • Hata iletisi. Hata kalıcı olmalıdır ve alanla ilişkilendirilmelidir; üzerine gelindiğinde beliren bir hata iletisi görülmeden kaybolur.

Karşı kalıp **açıklama baloncuğu (toggletip)**dur: gerçek bir düğmeyle açılır, tıklamayla çalışır, içeriği bir canlı bölgeye yazıldığı için duyurulur ve kullanıcı kapatana kadar durur. Ayrım tetikleyicidedir — üzerine gelme ve odakla açılan katman ipucu, tıklamayla açılan katman baloncuktur. Dokunmatik ekranda üzerine gelme olmadığı için, bilginin dokunmayla da gerekli olduğu her yerde doğru kalıp baloncuktur.

Yerel Öge Önce, ARIA Sonra

İşaretlemede bu iş için ayrılmış bir öznitelik vardır: title. Tanımı gereği danışma niteliğinde bilgi taşır ve nasıl sunulacağı kullanıcı aracına bırakılmıştır. Sunumun yazara bırakılmaması, ipucunun uyması gereken ölçütün tam olarak yazardan istediği şeyi — görünme süresini, kapatılabilmesini, üzerine gelinebilmesini — denetlenemez kılar. Bu yüzden araç ipucu, yerel karşılığın belirtimi karşılamadığı ender kalıplardan biridir ve elle kurulur.

Elle kurulumda dört bağ vardır:

Parça Kaynak
Katmanın rolü role="tooltip"
Denetimle bağ Tetikleyicide aria-describedby, ipucu kutusunun kimliğine
Denetimin adı İpucundan bağımsız; simge düğmede aria-label ile verilir
Görünürlük Katman gizliyken erişilebilirlik ağacında da bulunmaz

Ad ile açıklamanın ayrımı burada kritiktir. Yalnız simge taşıyan bir düğmenin ipucu çoğu zaman düğmenin adıyla aynı metni gösterir. Bu durumda metin bir açıklama değil bir addır ve aria-describedby ile bağlanması ada eklenmeyen ikinci bir kopya üretir; doğru kurulum metni aria-labelledby ile ada bağlamak ve ayrıca açıklama vermemektir.

Görünen metnin adın içinde bulunması ayrı bir ölçüte bağlıdır: 2.5.3 Etikette Ad. Sesle denetim kullanan biri ekranda okuduğu sözcüğü söyler; ad o sözcüğü içermiyorsa denetim çağrılamaz. İpucunda “Uzatma koşulları” yazıp adı “Yardım” olan bir düğme bu ölçütü karşılamaz.

Klavye ve Dokunma Sözleşmesi

Girdi Davranış
Odak Tetikleyici odak aldığında ipucu görünür, odak çıkınca gizlenir
İşaretçi Üzerine gelindiğinde görünür; işaretçi ipucunun üstüne geçebilir
Kaçış İpucunu gizler; odak tetikleyicide kalır
Dokunma İpucu görünmez; bilgi gerekliyse baloncuk kalıbına geçilir

İpucuna sekme tuşuyla gidilmez ve içine odak konmaz. Odak sırası tetikleyicide durur; ipucu yalnız görünür.

Gecikme iki yönlüdür. Açılma gecikmesi işaretçinin bir dizi ögenin üstünden geçerken art arda ipucu açmasını engeller. Kapanma gecikmesi işaretçinin tetikleyiciden ipucuna geçerken aradaki boşlukta kalması durumunda ipucunun kaybolmasını engeller. İkincisi bir tercih değil, ölçütün gereğidir.

Üç Koşulun ve Geometrinin Denetimi

1.4.13 Üzerine Gelme veya Odakla Beliren İçerik ölçütü üç koşul koyar: içerik kapatılabilir olmalı (imleci ya da odağı taşımadan gizlenebilmeli), üzerine gelinebilir olmalı (işaretçi içeriğin üstüne kaybolmadan geçebilmeli) ve kalıcı olmalı (üzerine gelme, odak ya da kapatma sona erene kadar durmalı). Üçü ayrı ayrı denetlenir; biri eksikse ölçüt karşılanmaz.

Üçüncü koşul geometriye bağlıdır: işaretçi tetikleyiciden ipucuna giderken aradaki boşlukta “üzerinde değil” durumuna düşerse ipucu kaybolur. Aşağıdaki betik önce üç koşulu kural olarak denetliyor, sonra işaretçinin izleyeceği iki yolu tarayıp kaç pikselinin katmanların dışında kaldığını ölçüyor.

// ipucu.mjs — arac ipucunun uc kosulu ve isaretcinin ipucuna ulasabilmesi

// --- (a) 1.4.13 uc kosulun kural denetimi -----------------------------------
// kapatilabilir: kacis tusu icerigi gizler
// kalici: kendiliginden gizlenme yok (otomatikGizlemeMs === null)
// uzerine gelinebilir: isaretci tetikleyiciden ipucuna gecerken icerik gizlenmiyor
const YAPILAR = [
  { ad: "yalniz uzerine gelme", kacisKapatir: false, otomatikGizlemeMs: 2000, gecisAlani: false },
  { ad: "odak + uzerine gelme", kacisKapatir: false, otomatikGizlemeMs: null, gecisAlani: false },
  { ad: "kacisla kapanan",      kacisKapatir: true,  otomatikGizlemeMs: 5000, gecisAlani: true  },
  { ad: "tam belirtim",         kacisKapatir: true,  otomatikGizlemeMs: null, gecisAlani: true  },
];

console.log("yapi                  kapatilabilir  kalici  uzerine gelinebilir  1.4.13");
for (const y of YAPILAR) {
  const kapatilabilir = y.kacisKapatir;
  const kalici = y.otomatikGizlemeMs === null;
  const gelinebilir = y.gecisAlani;
  console.log(
    `${y.ad.padEnd(21)} ${(kapatilabilir ? "evet" : "hayir").padStart(13)} ` +
      `${(kalici ? "evet" : "hayir").padStart(7)} ${(gelinebilir ? "evet" : "hayir").padStart(20)}  ` +
      `${kapatilabilir && kalici && gelinebilir ? "gecer" : "KALIR"}`,
  );
}

// --- (b) Isaretcinin ipucuna ulasmasi ---------------------------------------
// Tetikleyici: 24 x 24 piksellik simge dugme (satir sonundaki "ne demek" dugmesi).
// Ipucu kutusu: 180 x 36.
const TETIK = { x: 620, y: 300, g: 24, y2: 24 };
const IPUCU = { g: 180, y2: 36 };

const icinde = (n, k) => n.x >= k.x && n.x <= k.x + k.g && n.y >= k.y && n.y <= k.y + k.y2;
const ortusme = (a, b) => Math.max(0, Math.min(a.x + a.g, b.x + b.g) - Math.max(a.x, b.x));

// Bir kirikli yolu 0.5 px adimla tara; kutular birlesimi disinda kalan uzunlugu dondur.
function kopukUzunluk(nokta, kutular) {
  let kopuk = 0;
  for (let p = 0; p < nokta.length - 1; p++) {
    const [a, b] = [nokta[p], nokta[p + 1]];
    const uzunluk = Math.hypot(b.x - a.x, b.y - a.y);
    if (uzunluk === 0) continue;
    const adim = Math.ceil(uzunluk / 0.5);
    let disarida = 0;
    for (let i = 0; i <= adim; i++) {
      const n = { x: a.x + ((b.x - a.x) * i) / adim, y: a.y + ((b.y - a.y) * i) / adim };
      if (!kutular.some((k) => icinde(n, k))) disarida++;
    }
    kopuk += (disarida * uzunluk) / adim;
  }
  return kopuk;
}

function yerlesim({ yon, hiza, bosluk, kopru }) {
  const y = yon === "alt" ? TETIK.y + TETIK.y2 + bosluk : TETIK.y - bosluk - IPUCU.y2;
  const x =
    hiza === "basi" ? TETIK.x
    : hiza === "orta" ? TETIK.x + TETIK.g / 2 - IPUCU.g / 2
    : TETIK.x + TETIK.g - IPUCU.g;
  const ipucu = { x, y, g: IPUCU.g, y2: IPUCU.y2 };
  const kutular = [{ ...TETIK }];
  const ortak = ortusme(TETIK, ipucu);
  if (kopru && bosluk > 0 && ortak > 0) {
    kutular.push({
      x: Math.max(TETIK.x, ipucu.x),
      y: yon === "alt" ? TETIK.y + TETIK.y2 : TETIK.y - bosluk,
      g: ortak,
      y2: bosluk,
    });
  }
  kutular.push(ipucu);
  return { ipucu, kutular, ortak };
}

const merkez = (k) => ({ x: k.x + k.g / 2, y: k.y + k.y2 / 2 });

const SENARYOLAR = [
  { ad: "alt / ortalanmis / 0 px",         yon: "alt", hiza: "orta", bosluk: 0,  kopru: false },
  { ad: "alt / ortalanmis / 12 px",        yon: "alt", hiza: "orta", bosluk: 12, kopru: false },
  { ad: "alt / ortalanmis / 12 px + kopru",yon: "alt", hiza: "orta", bosluk: 12, kopru: true  },
  { ad: "alt / basa hizali / 8 px + kopru",yon: "alt", hiza: "basi", bosluk: 8,  kopru: true  },
  { ad: "ust / sona hizali / 8 px + kopru",yon: "ust", hiza: "sonu", bosluk: 8,  kopru: true  },
  { ad: "alt / kaydirilmis / 8 px + kopru",yon: "alt", hiza: "kaydirilmis", bosluk: 8, kopru: true },
];

console.log("\nyerlesim                         yatay ortusme  dik yol  dogrudan yol  uzerine gelinebilir");
for (const s of SENARYOLAR) {
  // "kaydirilmis": ipucu tetikleyicinin sag disina tasmis (ekran kenari duzeltmesi hatasi)
  const ayar = s.hiza === "kaydirilmis" ? { ...s, hiza: "basi" } : s;
  let { ipucu, kutular, ortak } = yerlesim(ayar);
  if (s.hiza === "kaydirilmis") {
    ipucu = { ...ipucu, x: TETIK.x + TETIK.g + 4 };
    ortak = ortusme(TETIK, ipucu);
    kutular = [{ ...TETIK }, ipucu];
  }
  const m = merkez(ipucu);
  const b = merkez(TETIK);
  const dik = kopukUzunluk([b, { x: b.x, y: m.y }, m], kutular);
  const dogrudan = kopukUzunluk([b, m], kutular);
  console.log(
    `${s.ad.padEnd(32)} ${(ortak.toFixed(0) + " px").padStart(13)} ` +
      `${(dik.toFixed(1) + " px").padStart(8)} ${(dogrudan.toFixed(1) + " px").padStart(13)}  ` +
      `${dik === 0 ? "evet" : "HAYIR"}`,
  );
}

// --- (c) Tetikleyicinin hedef boyutu ----------------------------------------
console.log(`\ntetikleyici hedefi: ${TETIK.g} x ${TETIK.y2} px, 2.5.8 esigi 24 x 24: ` +
  `${TETIK.g >= 24 && TETIK.y2 >= 24 ? "gecer" : "kalir"}`);
yapi                  kapatilabilir  kalici  uzerine gelinebilir  1.4.13
yalniz uzerine gelme          hayir   hayir                hayir  KALIR
odak + uzerine gelme          hayir    evet                hayir  KALIR
kacisla kapanan                evet   hayir                 evet  KALIR
tam belirtim                   evet    evet                 evet  gecer

yerlesim                         yatay ortusme  dik yol  dogrudan yol  uzerine gelinebilir
alt / ortalanmis / 0 px                  24 px   0.0 px        0.0 px  evet
alt / ortalanmis / 12 px                 24 px  11.5 px       11.5 px  HAYIR
alt / ortalanmis / 12 px + kopru         24 px   0.0 px        0.0 px  evet
alt / basa hizali / 8 px + kopru         24 px   0.0 px       32.4 px  evet
ust / sona hizali / 8 px + kopru         24 px   0.0 px       32.4 px  evet
alt / kaydirilmis / 8 px + kopru          0 px  42.0 px       46.3 px  HAYIR

tetikleyici hedefi: 24 x 24 px, 2.5.8 esigi 24 x 24: gecer

İlk tablo koşulların bağımsız olduğunu gösteriyor. Kaçış tuşuyla kapanan bir ipucu, beş saniye sonra kendiliğinden gizleniyorsa kalıcı değildir ve ölçüt yine karşılanmaz. Yavaş okuyan bir kullanıcı için beş saniye bir güvence değil, bir sınırdır.

İkinci tablo ölçütün üçüncü koşulunu piksel cinsinden veriyor. Yol taraması 0.5 piksellik adımlarla yapıldığı için sonuçlar bu adımın yarısı kadar aşağıdan yuvarlanır; 12 piksellik boşluk 11.5 piksel kopukluk olarak görünür.

Üç sonuç çıkar. Boşluk bırakmak yeter bir kusurdur: on iki piksellik görsel boşluk, işaretçinin on iki piksel boyunca “üzerinde değil” durumuna düşmesi demektir. Görünmez geçiş alanı boşluğu kapatır: iki kutunun yatay örtüşmesi kadar genişlikte, boşluğu dolduran bir alan, dik yolu kopmasız kılar. Yatay örtüşme sıfıra düştüğünde hiçbir alan yardım etmez: son satırda ipucu ekran kenarına sığmadığı için tetikleyicinin sağ dışına kaydırılmış ve iki kutunun ortak sütunu kalmamıştır; işaretçinin ipucuna ulaşacağı hiçbir dik yol yoktur.

Dördüncü ve beşinci satırlar ölçütü geçiyor ama doğrudan yolda otuz iki piksel kopukluk gösteriyor. Bu, uygunluk kusuru değil kullanılabilirlik maliyetidir: ipucunun merkezine nişan alan bir kullanıcı tetikleyicinin dışına çıkar. İpucunun tetikleyiciye ortalanması bu maliyeti sıfırlar; ölçüt yalnız bir yolun varlığını ister, tasarım doğal yolun da çalışmasını ister.

Ölçülebilir Kısıtlar

1.4.13 üç koşulu birlikte arar; tablo bu üçünü ayrı sütunlar hâlinde denetler.

2.5.8 Hedef Boyutu (En Az). Simge tetikleyici 24 x 24 piksellik eşiği karşılamalıdır; 16 piksellik bir simge çevresindeki etkin alanla bu boyuta genişletilir.

1.4.3 Kontrast (En Az) ve 1.4.11 Metin Dışı Kontrast. İpucu kutusunun metni zeminine karşı 4.5:1 oranını, kutunun kenarlığı ve varsa oku çevresindeki yüzeye karşı 3:1 oranını karşılamalıdır. Katman altındaki içeriğin üstüne düştüğü için ipucunun zemini saydam olamaz.

1.4.4 Metnin Yeniden Boyutlandırılması. Metin iki katına çıkarıldığında ipucu kutusu içeriğini kırpmadan büyümelidir; sabit yükseklikli bir ipucu bu eşikte metni keser.

1.4.12 Metin Aralığı. Satır yüksekliği ve harf aralığı artırıldığında kutu yine taşmamalıdır. İki ölçüt birlikte, ipucu kutusunun içerikle büyüyen bir kutu olmasını zorunlu kılar.

Sık Yapılan Hata ve Nasıl Anlaşılır

İpucu yalnız üzerine gelmeyle açılıyor. Klavye kullanıcısı bilgiye hiç ulaşamaz. Anlaşılması: tetikleyiciye sekme tuşuyla gidip ipucunun belirip belirmediğine bakmak.

İpucu düğmenin tek adı. Simge düğmenin aria-label değeri yoksa ve ad yalnız ipucunda yazılıysa, düğme erişilebilirlik ağacında adsızdır. Anlaşılması: ipucunu hiç açmadan düğmenin ad alanını okumak; otomatik denetleyicilerin varlık kuralı bu kusuru yakalar.

İpucu içinde bağlantı var. Kullanıcı bağlantıya ulaşmak için işaretçiyi ipucuna taşımak zorundadır ve klavyeyle hiç ulaşamaz. Anlaşılması: ipucu içeriğinde odaklanabilir öge aramak; bulunuyorsa kalıp yanlış seçilmiştir.

Süreli gizlenme. İpucu birkaç saniye sonra kendiliğinden kayboluyorsa ölçütün kalıcılık koşulu karşılanmaz. Anlaşılması: ipucunu açıp beklemek; kaybolan bir ipucu kusurludur.

Özet

  • Araç ipucu adı zaten olan bir denetime ek açıklama getirir; içindeki bilgi hiçbir zaman zorunlu olamaz ve ipucu denetimin adı yerine geçemez.
  • Etkileşimli içerik, uzun metin ve hata iletisi ipucuna girmez; tıklamayla açılan ve kullanıcı kapatana kadar duran açıklama baloncuğu bu işler için ayrı bir kalıptır.
  • title özniteliğinin sunumu kullanıcı aracına bırakıldığı için ölçütün istediği denetim yazarda kalmaz; ipucu elle kurulur ve role="tooltip" ile aria-describedby bağını taşır.
  • 1.4.13 üç bağımsız koşul arar: kapatılabilir, üzerine gelinebilir, kalıcı. Kaçış tuşuyla kapanan ama süreyle gizlenen bir ipucu ölçütü karşılamaz.
  • Üzerine gelinebilirlik geometriyle hesaplanır: tetikleyici ile ipucu arasındaki boşluk görünmez bir geçiş alanıyla kapatılmalı, yatay örtüşme sıfıra düşmemelidir.
  • İpucunun tetikleyiciye ortalanması, ölçütün istemediği ama doğal işaretçi yolunun gerektirdiği ek bir karardır.

Sonraki Adım

Araç ipucu kullanıcının bir ögeye yönelmesiyle belirdi; yani ne zaman görüneceğini kullanıcı belirledi. Sıradaki katman bu bağı da koparır: sistem bir şey olduğunda bildirimi kendisi gönderir, kullanıcı ekranın neresine bakıyor olursa olsun. Burada üç yeni soru doğar — bildirim ne kadar ekranda kalmalı, aynı anda gelen iki bildirim nasıl sıraya girmeli ve bildirim görsel kanalın dışına nasıl çıkmalı? Sonraki ders görünme süresini metnin okunma hızından hesaplar ve duyuru kuyruğunu art arda gelen bildirimlerle sınar.

İ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