İçeriğe geç
academia.sh

Ders 06 / 25

Bağlantı ve Düğme Ayrımı

Kaynak değişimine dayanan karar kuralı, iki bileşenin klavye sözleşmelerinin karşılaştırılması, yanlış eşlemenin ürettiği kayıpların sayımı ve bağlantı metni ölçütleri.

İçindekiler

Ödünç alma formundaki her denetim bir eylem çalıştırıyordu. Sonuç tablosundaki kayıt başlıkları ise başka bir iş yapar: kullanıcıyı kayıt ayrıntısı sayfasına götürür. İkisi sunum katmanında birbirinin yerine geçebilecek kadar benzetilebilir — bir bağlantı kutulu ve dolgulu çizilebilir, bir düğme altı çizili metin gibi görünebilir.

Ağaçta ise ikisi ayrıdır ve bu ayrım yalnızca bir adlandırma tercihi değildir: iki bileşenin klavye sözleşmesi, tarayıcının sunduğu ek olanaklar ve kullanıcının onlardan beklediği şey farklıdır. Bu ders ayrımı bir karar kuralına bağlar ve ihlalin ne kaybettirdiğini sayar.

Karar Kuralı

Kural tek cümledir: kullanıcı başka bir kaynağa gidiyorsa bağlantı, gitmiyorsa düğmedir. Ölçü, çalıştırma sonrasında adres çubuğundaki adresin değişip değişmediğidir; indirme de kaynağa erişme sayılır.

Kuralın işlettiği bazı durumlar sezgiye aykırı görünür. Süzgeç seçimlerini adrese yazan bir denetim — “Yalnız rafta olanlar” durumunu paylaşılabilir bir adres hâline getiren düzen — bağlantıdır, çünkü ürettiği şey başkasına gönderilebilen bir adrestir. Sayfanın içindeki bir bölüme atlayan denetim de bağlantıdır; hedefi belge parçasıdır ve tarayıcı geçmişine girer. Buna karşılık sonuç tablosunu yenileyen ama adresi değiştirmeyen bir süzgeç uygulaması düğmedir.

Yerel Öge Önce

Bağlantının karşılığı href özniteliği taşıyan a ögesidir; düğmenin karşılığı button ögesidir. href taşımayan bir a ögesi ağaçta anlamsız bir düğümdür: rol üretmez, odak almaz, tuş işlemez.

Bağlantı, düğmenin sağlamadığı dört olanağı getirir: adresin kopyalanması, bağlam menüsüyle yeni sekmede açılması, orta tuşla açılması ve yardımcı teknolojinin ürettiği bağlantı listesinde görünmesi. Bunların hiçbiri koda yazılabilecek şeyler değildir; tarayıcının bağlantı ögesine bağladığı davranışlardır.

Rol, Ad ve Durum

İki bileşenin de adı içeriğinden hesaplanır. Bağlantıda ek bir kısıt vardır: adın nereye gidildiğini söylemesi gerekir.

Sonuç tablosunda her satırın sonunda “Ayrıntı” yazan bir bağlantı bulunması yaygın bir düzendir. Kırk satırlık bir tabloda bu, ağaçta kırk tane aynı adlı bağlantı üretir. Bağlantı listesini açan kullanıcı kırk özdeş satır görür ve hiçbirinin nereye gittiğini bilemez. Çözüm, bağlantı metnini kaydın adına genişletmek ya da görünen metni gizli bir parçayla tamamlayıp adı “Yapıların Dili ayrıntısı” hâline getirmektir.

Bağlantının kalıcı bir durum bildirimi yoktur. Bulunulan sayfayı gösteren bağlantı aria-current="page" taşır; bu, bir durum değil, konumun bildirimidir ve gezinme bileşenlerinde ele alınır.

İki Klavye Sözleşmesi

Tuş / eylem Bağlantı Düğme
Tab Sekme durağıdır. Sekme durağıdır.
Enter Bağlantıyı izler. Düğmeyi çalıştırır.
Boşluk Sayfayı aşağı kaydırır. Düğmeyi çalıştırır.
Bağlam menüsü / orta tuş Yeni sekmede açar, adresi kopyalar. Karşılığı yoktur.

Boşluk tuşundaki fark, yanlış eşlemenin en görünür sonucudur. Bağlantı gibi kurulmuş bir eylem denetiminde boşluk tuşuna basan kullanıcı sayfayı kaydırır; düğme gibi kurulmuş bir gezinme denetiminde ise bağlam menüsünden “yeni sekmede aç” seçeneği hiç görünmez.

Eşlemenin Denetimi

// bag.mjs — baglanti ile dugme arasindaki kararin kurallastirilmasi ve denetimi

// Karar kurali: kaynak degisiyorsa (adres ya da indirme) baglanti, degilse dugme.
const karar = (n) => (n.adresDegisir || n.indirme ? "baglanti" : "dugme");

// Isaretlemeden uretilen davranis
function uretilen(m) {
  const baglantiMi = m.oge === "a" && m.href !== undefined;
  const dugmeMi = m.oge === "button";
  const rol = m.role ?? (baglantiMi ? "link" : dugmeMi ? "button" : "generic");
  return {
    rol,
    odaklanir: baglantiMi || dugmeMi || m.tabindex === 0,
    enter: baglantiMi || dugmeMi || m.tusIsler === true,
    bosluk: dugmeMi || m.tusIsler === true,
    yeniSekme: baglantiMi,          // baglam menusu ve orta tik yalniz adresi olanda calisir
    adresKopyalanir: baglantiMi,
    baglantiListesinde: rol === "link",
  };
}

// --- Katalog arayuzundeki denetimler ----------------------------------------
const ORNEKLER = [
  ['<a href="/kayit/K-118">Yapıların Dili</a>',
   { adresDegisir: true }, { oge: "a", href: "/kayit/K-118" }],
  ['<a href="#" tabindex="0">Süzgeci temizle</a>',
   { adresDegisir: false }, { oge: "a", href: "#", tusIsler: true }],
  ['<button>Kayıt ayrıntısı</button> (kodla gezinir)',
   { adresDegisir: true }, { oge: "button" }],
  ['<a href="/odunc/K-118" role="button">Ödünç al</a>',
   { adresDegisir: true }, { oge: "a", href: "/odunc/K-118", role: "button" }],
  ['<div tabindex="0">Ara</div>',
   { adresDegisir: false }, { oge: "div", tabindex: 0 }],
  ['<button type="submit">Ara</button>',
   { adresDegisir: false }, { oge: "button" }],
  ['<a href="/kunye/K-118.pdf" download>Künyeyi indir</a>',
   { adresDegisir: false, indirme: true }, { oge: "a", href: "/kunye/K-118.pdf" }],
  ['<span role="link" tabindex="0">Yardım</span>',
   { adresDegisir: true }, { oge: "span", role: "link", tabindex: 0 }],
];

const im = (b) => (b ? "var" : "yok");

console.log("isaretleme".padEnd(53) + "gereken".padEnd(10) + "rol".padEnd(10) +
  "Enter".padEnd(7) + "Bosluk".padEnd(8) + "yeni sekme".padEnd(12) + "bag. listesi");
for (const [kaynak, niyet, m] of ORNEKLER) {
  const u = uretilen(m);
  console.log(kaynak.padEnd(53) + karar(niyet).padEnd(10) + u.rol.padEnd(10) +
    im(u.enter).padEnd(7) + im(u.bosluk).padEnd(8) + im(u.yeniSekme).padEnd(12) +
    im(u.baglantiListesinde));
}

console.log("\nkural denetimi:");
let bulgu = 0;
for (const [kaynak, niyet, m] of ORNEKLER) {
  const g = karar(niyet);
  const u = uretilen(m);
  const b = [];
  if (g === "baglanti" && u.rol !== "link")
    b.push("gezinme dugme olarak bildirildi: adres kopyalanamaz, yeni sekmede acilamaz");
  if (g === "dugme" && u.rol === "link")
    b.push("eylem baglanti olarak bildirildi: gecmise kayit girer, hedef adres anlamsiz");
  if (!u.odaklanir) b.push("klavyeyle odaklanilamaz");
  if (!u.enter) b.push("giris tusu calismiyor");
  if (u.rol === "button" && !u.bosluk) b.push("dugme rolu bildirildi, bosluk tusu calismiyor");
  if (u.rol === "link" && m.oge !== "a") b.push("baglanti rolu bildirildi, adres yok");
  for (const x of b) { bulgu++; console.log("  " + kaynak.padEnd(53) + x); }
}
console.log(`\n${ORNEKLER.length} ornekte ${bulgu} bulgu`);

// --- Karar tablosu ----------------------------------------------------------
console.log("\nkarar tablosu:");
console.log("davranis".padEnd(40) + "bilesen");
const DAVRANISLAR = [
  ["kayit ayrinti sayfasina gider", { adresDegisir: true }],
  ["sonuc tablosunu suzer, adres degismez", { adresDegisir: false }],
  ["suzgec durumunu adrese yazar", { adresDegisir: true }],
  ["kunye dosyasini indirir", { adresDegisir: false, indirme: true }],
  ["odunc alma istegini gonderir", { adresDegisir: false }],
  ["sayfa icindeki bir bolume atlar", { adresDegisir: true }],
];
for (const [ad, n] of DAVRANISLAR) console.log(ad.padEnd(40) + karar(n));
isaretleme                                           gereken   rol       Enter  Bosluk  yeni sekme  bag. listesi
<a href="/kayit/K-118">Yapıların Dili</a>            baglanti  link      var    yok     var         var
<a href="#" tabindex="0">Süzgeci temizle</a>         dugme     link      var    var     var         var
<button>Kayıt ayrıntısı</button> (kodla gezinir)     baglanti  button    var    var     yok         yok
<a href="/odunc/K-118" role="button">Ödünç al</a>    baglanti  button    var    yok     var         yok
<div tabindex="0">Ara</div>                          dugme     generic   yok    yok     yok         yok
<button type="submit">Ara</button>                   dugme     button    var    var     yok         yok
<a href="/kunye/K-118.pdf" download>Künyeyi indir</a>baglanti  link      var    yok     var         var
<span role="link" tabindex="0">Yardım</span>         baglanti  link      yok    yok     yok         var

kural denetimi:
  <a href="#" tabindex="0">Süzgeci temizle</a>         eylem baglanti olarak bildirildi: gecmise kayit girer, hedef adres anlamsiz
  <button>Kayıt ayrıntısı</button> (kodla gezinir)     gezinme dugme olarak bildirildi: adres kopyalanamaz, yeni sekmede acilamaz
  <a href="/odunc/K-118" role="button">Ödünç al</a>    gezinme dugme olarak bildirildi: adres kopyalanamaz, yeni sekmede acilamaz
  <a href="/odunc/K-118" role="button">Ödünç al</a>    dugme rolu bildirildi, bosluk tusu calismiyor
  <div tabindex="0">Ara</div>                          giris tusu calismiyor
  <span role="link" tabindex="0">Yardım</span>         giris tusu calismiyor
  <span role="link" tabindex="0">Yardım</span>         baglanti rolu bildirildi, adres yok

8 ornekte 7 bulgu

karar tablosu:
davranis                                bilesen
kayit ayrinti sayfasina gider           baglanti
sonuc tablosunu suzer, adres degismez   dugme
suzgec durumunu adrese yazar            baglanti
kunye dosyasini indirir                 baglanti
odunc alma istegini gonderir            dugme
sayfa icindeki bir bolume atlar         baglanti

Bulguların Okunması

Boş adresli bağlantı iki kez yanlıştır. İkinci satırdaki süzgeç temizleme denetimi bir eylemdir ama bağlantı olarak bildirilmiş. İki sonucu var: tarayıcı geçmişine anlamsız bir kayıt girer ve kullanıcı geri düğmesine bastığında hiçbir şey olmaz; bağlantı listesinde hedefi olmayan bir satır belirir. Kullanıcının bağlam menüsünden yeni sekmede açması ise boş bir sayfa getirir.

Rol bildirimi bağlantıyı düğme yapmaz. Dördüncü satır bunu gösteriyor. role="button" yazıldığında ağaçtaki rol değişiyor, ancak öge hâlâ bir bağlantıdır: boşluk tuşu çalışmıyor, yeni sekmede açılma olanağı duruyor. Ekranda düğme, ağaçta düğme, davranışta bağlantı olan bir bileşen ortaya çıkıyor ve üçü birbiriyle çelişiyor.

Rol bildirimi davranış da eklemez. Son satırdaki role="link" taşıyan span ögesi odaklanabilir, çünkü tabindex yazılmış; ama giriş tuşuna yanıt vermiyor ve gidilecek bir adres taşımıyor. Bağlantı listesinde görünüyor, seçildiğinde hiçbir yere gitmiyor.

Düğmeyle yapılan gezinme sessizce kayıp üretir. Üçüncü satırda ekranda hiçbir kusur görünmez: düğme odak alır, giriş ve boşluk tuşlarıyla çalışır, sayfa açılır. Kaybolan şey, bağlantının getirdiği dört olanaktır. Kullanıcı kayıt ayrıntısını yeni sekmede açamaz, adresini kopyalayamaz ve bağlantı listesinde bulamaz.

Ölçülebilir Kısıtlar

2.4.4 Bağlantı Amacı (Bağlam İçinde), bağlantının amacının kendi metninden ya da bulunduğu bağlamdan anlaşılmasını ister; 2.4.9 Bağlantı Amacı (Yalnız Bağlantıdan) aynı şeyi yalnız metinden ister ve AAA düzeyindedir. Tablodaki “Ayrıntı” bağlantıları birinciyi tablo bağlamı sayesinde karşılar, ikinciyi karşılamaz.

1.4.1 Rengin Tek Taşıyıcı Olmaması, metin içindeki bağlantıların çevresindeki metinden yalnız renkle ayrılmamasını ister. Altını çizmek bu koşulu doğrudan karşılar. Renk ayrımı yeterli sayılacaksa iki koşul birden gerekir: bağlantı renginin çevre metinle en az 3:1 kontrast oranı taşıması ve odak ya da üzerine gelme durumunda ikinci bir görsel ayrımın belirmesi.

2.5.8 Hedef Boyutu, metin içindeki bağlantıları satır içi istisnasıyla kapsam dışında bırakır; bir paragrafın ortasındaki bağlantının yüksekliği satır yüksekliğine bağlıdır ve büyütülmesi metni bozar. Sonuç tablosundaki bağlantılar ise satır içi değildir ve ölçüte girer.

3.2.5 İstek Üzerine Değişiklik, yeni bir pencere açılmasını kullanıcının isteğine bağlar. Yeni sekmede açan bir bağlantı varsa, bu davranış adının parçası olarak bildirilmelidir; ekranda beliren küçük bir simge, alternatif metni yoksa hiçbir şey bildirmez.

Sık Yapılan Hata

Adressiz bağlantı. Saptaması araçsızdır: href taşımayan ya da değeri # olan her a ögesi bir bulgudur. Otomatik denetleyicilerin varlık kuralı bunu yakalar.

Aynı adlı çok sayıda bağlantı. Saptaması bir teklik denetimidir: sayfadaki bağlantı adları toplanır, aynı ada sahip olup farklı adreslere giden çiftler listelenir.

Görünüşün kararı belirlemesi. “Bu bir düğme gibi görünsün” gerekçesiyle bağlantı kurulması ya da tersi. Saptaması karar tablosudur: bileşenin ne yaptığı sorulur, görünüşü sorulmaz. Görsel ağırlık her iki bileşene de bağımsız olarak verilebilir.

Özet

  • Karar kuralı tek cümledir: kullanıcı başka bir kaynağa gidiyorsa bağlantı, gitmiyorsa düğme; indirme de kaynağa erişme sayılır.
  • Bağlantı, adresin kopyalanması, yeni sekmede açılması, orta tuşla açılması ve bağlantı listesinde görünmesi olanaklarını getirir; bunlar koda yazılamaz.
  • Giriş tuşu ikisinde de çalışır, boşluk tuşu yalnız düğmede çalıştırır; bağlantıda sayfayı kaydırır.
  • Rol bildirimi ne davranışı değiştirir ne de ekler; role="button" taşıyan bir bağlantı ekranda, ağaçta ve davranışta birbiriyle çelişen bir bileşen üretir.
  • Bağlantı adı nereye gidildiğini söylemelidir; tabloda yinelenen “Ayrıntı” metinleri 2.4.9 ölçütünü karşılamaz.
  • Metin içindeki bağlantılar 2.5.8 hedef boyutu ölçütünün satır içi istisnasına girer, tablo satırındaki bağlantılar girmez.

Sonraki Adım

Bu konu tek tek denetimleri belirtti; her birinin sınırı kendi kutusuydu. Sonuç tablosunun kart görünümünde ise sınır belirsizleşir: bir kart görsel, başlık, yazar, yıl ve iki denetim taşır ve tasarımcı kartın tamamının tıklanabilir olmasını ister. O istek, tek bir bağlantının içine ikinci bir denetim koymayı gerektirir ve kalıp burada kırılır. Sonraki ders kartı belirtir: içerik gruplamanın nasıl bildirileceğini, tıklanabilirlik sorununun üç çözümünü ve her birinin sekme durağı sayısına ne yaptığını hesaplar.

İ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