Ders 12 / 25
Tablolar
İki eksenli konumun işaretlemede kurulması, satır ve sütun başlığı ilişkisi, sıralama durumunun bildirimi ile duyurusu ve yoğun veride sekme sırasının denetim altında tutulması.
İçindekiler
Önceki ders sonuç listesinin konumunu bildirir hâle getirdi. Katalogda aynı veri çoğu zaman bir listeden daha fazlasıdır: raf kodu, başlık, yıl ve durum sütunlara ayrılır, sütunlar sıralanabilir ve satır sayısı yüzleri bulur. Bu yapıya tablo denir ve tabloda konum iki eksenlidir — kullanıcı hem bir satırda hem bir sütundadır.
Görsel okuyucu bu iki ekseni bakışla birleştirir: bir hücreye bakar, yukarı doğru sütun başlığını, sola doğru satır başlığını görür. Ekranı görmeyen kullanıcı bu birleştirmeyi yapamaz; hücrenin hangi başlıklara bağlı olduğu işaretlemede yazılı olmak zorundadır.
Kalıbın Çözdüğü Sorun ve Kullanılmayacağı Yer
Tablo, iki boyutlu ilişkisel veriyi sunar: her satır bir varlık, her sütun o varlığın bir niteliğidir. Bir veri tablonun içine ancak bu ilişki gerçekten varsa girer.
Düzen kurmak için tablo kullanmak bu ilişkiyi uydurur: ekranı görmeyen kullanıcıya var olmayan bir satır–sütun yapısı bildirilir ve içerik anlamsız bir ızgaraya dönüşür. Düzen işi Düzen Sistemleri kursundaki ızgara modellerinin işidir; tablo ögesi yalnız veri tablosu içindir.
Yerel Öge Önce ve Başlık İlişkisi
Tablonun yerel karşılığı eksiksizdir: tablo ögesi, özet başlığı, başlık hücreleri ve veri hücreleri. Başlık hücresi sütun ya da satır başlığı olduğunu kapsam bildirimiyle söyler. Bu bildirim yazıldığında hücre–başlık ilişkisi kendiliğinden kurulur; ARIA’ya gerek kalmaz.
Aşağıdaki hesap bu ilişkiyi bir model üzerinde kuruyor ve satır başlığı işaretlenmediğinde neyin kaybolduğunu sayıyor.
// tablo.mjs — baslik-hucre iliskisi, siralama durumu ve yogun veride gezinme // Tablo modeli: basliklar, satirlar ve her hucrenin degeri. const TABLO = { ozet: "Kuzey Yamaç ölçüm kayıtları", sutunlar: [ { anahtar: "kod", ad: "Raf kodu", tur: "metin", siralanabilir: true }, { anahtar: "baslik", ad: "Başlık", tur: "metin", siralanabilir: true, satirBasligi: true }, { anahtar: "yil", ad: "Yıl", tur: "sayi", siralanabilir: true }, { anahtar: "durum", ad: "Durum", tur: "metin", siralanabilir: false }, ], satirlar: [ { kod: "QB-141", baslik: "Gökbilim El Kitabı", yil: 1998, durum: "rafta" }, { kod: "QB-212", baslik: "Kuzey Gökyüzü Atlası", yil: 2004, durum: "ödünçte" }, { kod: "QC-018", baslik: "Ölçüm Yöntemleri", yil: 2011, durum: "rafta" }, ], }; // 1. Baslik-hucre iliskisi: her veri hucresinin bagli oldugu basliklar. // Kural: sutun basligi tablonun ust satirindan, satir basligi o satirin // "satirBasligi" isaretli sutunundan gelir. const satirBasligiSutunu = TABLO.sutunlar.find((s) => s.satirBasligi); console.log("--- baslik-hucre iliskisi ---"); console.log("hucre bagli basliklar"); let baglisiz = 0; for (const satir of TABLO.satirlar) { for (const sutun of TABLO.sutunlar) { if (sutun.satirBasligi) continue; const basliklar = [sutun.ad, satirBasligiSutunu ? satir[satirBasligiSutunu.anahtar] : null].filter(Boolean); if (basliklar.length < 2) baglisiz++; console.log(` ${String(satir[sutun.anahtar]).padEnd(24)} ${basliklar.join(" / ")}`); } } console.log(`iki baslikla da eslesmeyen hucre: ${baglisiz}`); // 2. Ayni tablo satir basligi isaretlenmeden kurulursa. const satirBasligisiz = { ...TABLO, sutunlar: TABLO.sutunlar.map((s) => ({ ...s, satirBasligi: false })) }; const eksikEslesme = satirBasligisiz.satirlar.length * (satirBasligisiz.sutunlar.length - 0); console.log(`\nsatir basligi isaretlenmezse: her hucre yalniz sutun adiyla eslesir`); console.log(` eslesme sayisi: hucre basina 1 (satir kimligi kayboluyor)`); console.log(` etkilenen hucre: ${eksikEslesme}`); // 3. Siralama durumu: yalniz bir sutun siralanmis olabilir. function siralamaDurumu(sutunAnahtari, yon) { return TABLO.sutunlar.map((s) => ({ ad: s.ad, siralanabilir: s.siralanabilir, durum: !s.siralanabilir ? "-" : s.anahtar === sutunAnahtari ? yon : "none", })); } const durum = siralamaDurumu("yil", "ascending"); console.log("\n--- siralama durumu ---"); console.log("sutun siralanabilir aria-sort"); for (const d of durum) console.log(` ${d.ad.padEnd(11)} ${(d.siralanabilir ? "evet" : "hayir").padEnd(14)} ${d.durum}`); const isaretli = durum.filter((d) => d.durum !== "none" && d.durum !== "-").length; console.log(`isaretli sutun: ${isaretli} (kural: en cok 1)`); // 4. Siralamadan sonra duyurulacak dizgi. const yonAdi = { ascending: "artan", descending: "azalan" }; function duyuru(sutunAd, yon, satirSayisi) { return `${sutunAd} sütununa göre ${yonAdi[yon]} sıralandı, ${satirSayisi} satır`; } console.log(`\nduyuru: "${duyuru("Yıl", "ascending", TABLO.satirlar.length)}"`); console.log(`duyuru: "${duyuru("Başlık", "descending", TABLO.satirlar.length)}"`); // 5. Siralamanin kendisi: veri turu karsilastirmayi belirler. const karsilastir = (tur) => tur === "sayi" ? (a, b) => a - b : (a, b) => String(a).localeCompare(String(b), "tr"); console.log("\n--- siralama sonucu (yil, artan) ---"); for (const s of [...TABLO.satirlar].sort((a, b) => karsilastir("sayi")(a.yil, b.yil))) { console.log(` ${String(s.yil).padEnd(6)} ${s.baslik}`); } console.log("--- siralama sonucu (baslik, artan; tr harf sirasi) ---"); for (const s of [...TABLO.satirlar].sort((a, b) => karsilastir("metin")(a.baslik, b.baslik))) { console.log(` ${s.baslik}`); } // 6. Yogun veride sekme duragi sayisi: her hucre odaklanabilir yapilirsa ne olur? const SATIR = 200, SUTUN = 4; const hepsiOdaklanabilir = SATIR * SUTUN; const yalnizEylemler = SATIR * 1 + SUTUN; // satir basina bir eylem + sutun basliklari console.log("\n--- sekme duragi sayisi (200 satir, 4 sutun) ---"); console.log(` her hucre odaklanabilir : ${hepsiOdaklanabilir}`); console.log(` yalniz eylemler + basliklar: ${yalnizEylemler}`); console.log(` oran: ${(hepsiOdaklanabilir / yalnizEylemler).toFixed(1)} kat`); // 7. Sutun sayisi tutarliligi: eksik hucre denetimi. const bozukSatir = { kod: "QC-100", baslik: "Eksik Kayıt" }; // yil ve durum yok const denetlenen = [...TABLO.satirlar, bozukSatir]; console.log("\n--- sutun sayisi tutarliligi ---"); for (const s of denetlenen) { const eksik = TABLO.sutunlar.filter((c) => s[c.anahtar] === undefined).map((c) => c.ad); console.log(` ${(s.kod || "-").padEnd(8)} eksik alan: ${eksik.length ? eksik.join(", ") : "yok"}`); }
--- baslik-hucre iliskisi --- hucre bagli basliklar QB-141 Raf kodu / Gökbilim El Kitabı 1998 Yıl / Gökbilim El Kitabı rafta Durum / Gökbilim El Kitabı QB-212 Raf kodu / Kuzey Gökyüzü Atlası 2004 Yıl / Kuzey Gökyüzü Atlası ödünçte Durum / Kuzey Gökyüzü Atlası QC-018 Raf kodu / Ölçüm Yöntemleri 2011 Yıl / Ölçüm Yöntemleri rafta Durum / Ölçüm Yöntemleri iki baslikla da eslesmeyen hucre: 0 satir basligi isaretlenmezse: her hucre yalniz sutun adiyla eslesir eslesme sayisi: hucre basina 1 (satir kimligi kayboluyor) etkilenen hucre: 12 --- siralama durumu --- sutun siralanabilir aria-sort Raf kodu evet none Başlık evet none Yıl evet ascending Durum hayir - isaretli sutun: 1 (kural: en cok 1) duyuru: "Yıl sütununa göre artan sıralandı, 3 satır" duyuru: "Başlık sütununa göre azalan sıralandı, 3 satır" --- siralama sonucu (yil, artan) --- 1998 Gökbilim El Kitabı 2004 Kuzey Gökyüzü Atlası 2011 Ölçüm Yöntemleri --- siralama sonucu (baslik, artan; tr harf sirasi) --- Gökbilim El Kitabı Kuzey Gökyüzü Atlası Ölçüm Yöntemleri --- sekme duragi sayisi (200 satir, 4 sutun) --- her hucre odaklanabilir : 800 yalniz eylemler + basliklar: 204 oran: 3.9 kat --- sutun sayisi tutarliligi --- QB-141 eksik alan: yok QB-212 eksik alan: yok QC-018 eksik alan: yok QC-100 eksik alan: Yıl, Durum
Satır Başlığı Kimliği Taşır
Çıktının ilk bölümü her veri hücresinin iki başlığa bağlandığını gösteriyor: sütun adı ve satırın kimliği. “1998” değeri tek başına bir sayıdır; “Yıl / Gökbilim El Kitabı” bağlamı onu bir bilgiye çevirir.
İkinci bölüm satır başlığı işaretlenmediğinde ne olduğunu sayıyor: on iki hücrenin her biri yalnız sütun adıyla eşleşiyor, satır kimliği kayboluyor. Hücreler arasında gezen kullanıcı “1998” duyar ama hangi kaydın yılı olduğunu bilemez. Her satırda bir hücre — genellikle adı ya da kimliği taşıyan hücre — satır başlığı olarak işaretlenir.
Sıralama Durumu Bir Bildirimdir
Üçüncü bölüm sıralama durumunu denetliyor. Kural iki parçalıdır. Birincisi, sıralanabilir her sütun başlığının sıralama durumunu bildirmesi gerekir; sıralanabilir olmayan sütun bu bildirimi hiç taşımaz. İkincisi, aynı anda en çok bir sütun sıralanmış olabilir; iki sütunun birden işaretli görünmesi, kullanıcıya çelişkili bir durum bildirir.
Sıralama denetiminin kendisi başlık hücresinin içindeki bir düğmedir. Başlık hücresini tıklanabilir yapmak yerine düğme kullanmanın nedeni Bağlantı ve Düğme Ayrımı dersinde kurulmuştu: eylem düğmedir, düğme klavyeden erişilir ve rolüyle bildirilir.
Sıralamadan Sonra Ne Duyurulur
Dördüncü bölüm duyuru dizgisini üretiyor. Sıralama sayfayı değiştirmez, tablonun içeriğini yeniden düzenler; bu değişiklik görsel olarak anında görünür ama duyurulmazsa ekranı görmeyen kullanıcı için sessizdir.
Duyuru üç bilgiyi taşır: hangi sütun, hangi yön, kaç satır. Satır sayısının bulunması önemlidir, çünkü sıralama süzgeçle birlikte çalıştığında satır sayısı da değişebilir. Duyuru kibar bir canlı bölgeden verilir; sıralama kullanıcının kendi eylemidir ve kesintiye uğratmayı gerektirmez.
Beşinci bölüm sıralamanın kendisini gösteriyor: karşılaştırma veri türüne bağlıdır. Sayı sütunu sayısal, metin sütunu dile duyarlı karşılaştırmayla sıralanır. Türkçe metinlerde dizgi karşılaştırması yerel ayara verilmezse harf sırası bozulur — bu, Uluslararasılaştırma API’si dersinde kurulan kuralın tablo tarafındaki karşılığıdır.
Yoğun Veride Gezinme
Altıncı bölüm bir sayıyı ortaya koyuyor: iki yüz satırlık bir tabloda her hücre odaklanabilir yapılırsa sekme sırasına sekiz yüz durak girer. Yalnız eylemler ve sütun başlıkları odaklanabilir olduğunda bu sayı iki yüz dörde iner — yaklaşık dörtte bir.
Tablo hücreleri arasında ok tuşlarıyla gezinme, ancak tablo bir ızgara denetimi olarak kurulduğunda gerekir: hücreler düzenlenebiliyorsa ya da hücre seçimi bir eylemse. Salt okunur bir veri tablosunda hücreler odaklanabilir yapılmaz; kullanıcı içeriği okuma kipiyle gezer ve sekme sırası yalnız eylemleri taşır.
Son bölüm sütun sayısı tutarlılığını denetliyor. Eksik hücre bırakan bir satır, başlık eşlemesini kaydırır ve okuma sırasında değerler yanlış başlıkla eşleşir. Boş bir hücre bilinçli olarak boş bırakılabilir; eksik hücre bir kusurdur.
Klavye Sözleşmesi
| Tuş | Davranış |
|---|---|
Tab |
Bir sonraki eyleme geçer: sıralama düğmesi, satır içi eylem, sayfalama |
Enter / Boşluk |
Odaktaki sıralama düğmesini çalıştırır, yönü değiştirir |
| Ok tuşları | Salt okunur tabloda tablo kısayolu değildir; okuma kipinin kendi gezinmesi çalışır |
Ölçülebilir Kısıtlar
- Sıralanabilir her başlık hücresi sıralama durumunu bildirir ve aynı anda en çok biri sıralanmış olur.
- Her satırda bir hücre satır başlığı olarak işaretlenir; sütun başlıkları kapsamını bildirir (WCAG 1.3.1).
- Sıralama düğmesinin hedef boyutu 24×24 pikselden küçük olamaz (WCAG 2.5.8); başlık hücresinin tamamı tıklanabilir yapılıyorsa bu ölçü zaten sağlanır.
- Sıralama yönü yalnız bir ok simgesiyle bildirilemez; durum bildirimi metinsel kanaldır (WCAG 1.4.1).
- Yatay kaydırma gereken geniş tablolarda kaydırılabilir kap klavyeyle erişilebilir olmalıdır.
Sık Yapılan Hata
En sık hata, tabloyu düzen aracı olarak kullanmaktır. İkincisi, başlık hücrelerini biçimlendirilmiş veri hücresi olarak yazmaktır: kalın ve ortalanmış bir veri hücresi görsel olarak başlığa benzer ama hiçbir hücreyle ilişkilendirilmez. Üçüncüsü, sıralamayı yalnız simgeyle bildirmek ve durum bildirimini atlamaktır; bu durumda sıralamanın hangi sütunda olduğu klavye kullanıcısına hiç ulaşmaz.
Özet
- Tabloda konum iki eksenlidir; hücrenin hangi satır ve sütun başlığına bağlı olduğu işaretlemede yazılır, bakışla kurulan ilişki varsayılamaz.
- Satır başlığı işaretlenmediğinde her hücre yalnız sütun adıyla eşleşir ve satır kimliği kaybolur; modelde on iki hücrenin tamamı etkileniyor.
- Sıralanabilir sütun sıralama durumunu bildirir, aynı anda en çok bir sütun işaretlidir ve sıralama sonrası duyuru sütun, yön ve satır sayısını taşır.
- Karşılaştırma veri türüne bağlıdır; metin sütunları dile duyarlı sıralanır.
- Salt okunur tabloda hücreler odaklanabilir yapılmaz: iki yüz satırlık tabloda bu karar sekme durağı sayısını sekiz yüzden iki yüz dörde indirir.
Sonraki Adım
Bu bileşenlerin hepsinde içerik yerinde durdu ve kullanıcı ona kendi hızıyla ulaştı. Katalog ana sayfasındaki öne çıkan kayıtlar şeridi ise tersini yapar: içerik kendiliğinden değişir, kullanıcı okumayı bitirmeden bir sonraki karta geçer. Sonraki ders bu kalıbı ele alır ve otomatik geçişin maliyetini ölçütlerle yazar: hareketin durdurulabilir olması, okuma süresiyle geçiş aralığı arasındaki ilişki ve kendiliğinden değişen içeriğin duyurulmasının neden çoğu zaman yanlış olduğu.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.