---
title: Kartlar
source: 'https://academia.sh/tr/kurslar/erisilebilir-kaliplar/kartlar'
course: 'Erişilebilir Bileşen Kalıpları'
language: tr
updated: '2026-08-17T18:09:33+00:00'
license: 'CC BY-SA 4.0'
---

# Kartlar

Kartın bir bileşen değil bir gruplama düzeni olduğu; üç tıklanabilirlik kalıbının sekme durağı, erişilebilir ad ve iç içe yerleşim bakımından hesaplanması.

Önceki konu tek tek denetimleri belirtti ve her denetimin sınırı kendi kutusuydu. Sonuç
listesinin kart görünümünde bu sınır belirsizleşir. Bir kart görsel, başlık, yazar, yıl,
durum rozeti ve iki denetim taşır; tasarım kararı ise kartın **tamamının** tıklanabilir
olmasıdır.

İstek makuldür: kullanıcı kartın herhangi bir yerine tıkladığında kayıt ayrıntısına
gitmelidir. Ancak kartın içinde bir düğme de vardır ve iki denetim iç içe geçemez. Bu ders
kartı belirtir ve tıklanabilirlik sorununun üç çözümünü sayarak karşılaştırır.

## Kart Bir Bileşen Değil, Bir Düzendir

Kartın çözdüğü sorun, **türü farklı bilgilerin** bir arada taranabilir bir birim olarak
sunulmasıdır: bir görsel, bir başlık, iki üstveri satırı ve bir durum. Görsel gruplamanın
ölçütü Arayüz Tasarımının Temelleri kursundaki ortak bölge ilkesidir; bir yüzey, içindekileri
tek bir birim olarak okutur.

Kart kullanılmayacağı yer de bundan çıkar: bilgiler türdeş ve karşılaştırılabilir olduğunda
kart değil tablo kullanılır. Kırk kaydın yayın yılına göre karşılaştırılması gerekiyorsa
kart görünümü her değeri farklı bir dikey konuma yerleştirir ve karşılaştırmayı olanaksız
kılar.

## Yerel Öge Önce

Kartın bir öge karşılığı yoktur, çünkü bir denetim değildir. İşaretlemesi iki karardan
oluşur.

Birincisi, kart listesinin bir **liste** olarak yazılmasıdır. `ul` ve `li` ögeleri ağaca
liste rolünü ve öge sayısını bildirir; kullanıcı listeye girdiğinde kaç kayıt olduğunu
öğrenir. `div` yığınıyla kurulan bir ızgarada bu sayı hiçbir yerde bulunmaz.

İkincisi, kartın içinde bir **başlık ögesinin** bulunmasıdır. Başlık, kaydı ana hatta
yerleştirir ve başlık listesinden gezinen kullanıcıya kırk kaydı tek tek okumadan geçme
olanağı verir. Kart bağımsız olarak dağıtılabilir bir birimse `article` ögesiyle sarılır ve
`aria-labelledby` ile başlığa bağlanarak ağaçta adlandırılmış bir bölge olur.

## Tıklanabilirlik Sorununun Üç Çözümü

**A. Kartın tamamı bir bağlantıdır.** Görsel de, başlık da, özet de bağlantının içindedir.
İçindeki düğme de öyle.

**B. Yalnız başlık bağlantıdır, yüzey ona yayılır.** Bağlantı sözde bir elemanla kartın
tamamını kaplar; düğme sunum katmanında bu kaplamanın üstüne çıkarılır.

**C. Her parça ayrı bağlantıdır.** Görsel, başlık ve "Ayrıntı" bağlantısı aynı hedefe gider.

```js
// kart.mjs — kart kaliplarinda sekme duragi sayisi, erisilebilir ad ve ic ice yerlesim

const KART = {
  baslik: "Yapıların Dili",
  yazar: "T. Aksoy",
  yil: "2019",
  durum: "Rafta",
  ozet: "Yapı çözümlemesine giriş niteliğinde bir el kitabı.",
};

// Dugum: { oge, oz, cocuklar }  — metin dugumleri dizgi olarak durur
const etkilesimli = (d) =>
  (d.oge === "a" && d.oz?.href !== undefined) || d.oge === "button";

function odakDuraklari(d, yol = []) {
  if (typeof d === "string") return [];
  const bu = etkilesimli(d) ? [[...yol, d.oge + (d.oz?.href ? "[href]" : "")].join(" > ")] : [];
  const alt = (d.cocuklar ?? []).flatMap((c) => odakDuraklari(c, etkilesimli(d) ? [...yol, d.oge] : yol));
  return [...bu, ...alt];
}

function metin(d) {
  if (typeof d === "string") return d;
  const o = d.oz ?? {};
  if (o["aria-hidden"]) return "";
  if (d.oge === "img") return o.alt ?? "";
  return (d.cocuklar ?? []).map(metin).join(" ").replace(/\s+/g, " ").trim();
}

// Etkilesimli ogenin erisilebilir adi: aria-label > icerik metni
function ad(d) {
  const o = d.oz ?? {};
  if (o["aria-label"]) return o["aria-label"];
  return metin(d);
}

// Ic ice etkilesimli oge sayisi (bir baglantinin icindeki dugme/baglanti)
function icIce(d, icerideyiz = false) {
  if (typeof d === "string") return 0;
  const bu = icerideyiz && etkilesimli(d) ? 1 : 0;
  return bu + (d.cocuklar ?? []).reduce(
    (t, c) => t + icIce(c, icerideyiz || etkilesimli(d)), 0);
}

const govde = () => [
  { oge: "img", oz: { alt: "" } },
  { oge: "h3", cocuklar: [KART.baslik] },
  { oge: "p", cocuklar: [KART.yazar + ", " + KART.yil] },
  { oge: "p", cocuklar: [KART.ozet] },
  { oge: "span", cocuklar: [KART.durum] },
];

// A: kartin tamami tek baglanti; icinde ayrica bir dugme var
const A = {
  oge: "article",
  cocuklar: [
    { oge: "a", oz: { href: "/kayit/K-118" },
      cocuklar: [...govde(), { oge: "button", cocuklar: ["Ödünç al"] }] },
  ],
};

// B: yalnizca baslik baglanti; dugme kardes; kart yuzeyi baglantiya yayiliyor
const B = {
  oge: "article",
  cocuklar: [
    { oge: "img", oz: { alt: "" } },
    { oge: "h3", cocuklar: [{ oge: "a", oz: { href: "/kayit/K-118" }, cocuklar: [KART.baslik] }] },
    { oge: "p", cocuklar: [KART.yazar + ", " + KART.yil] },
    { oge: "p", cocuklar: [KART.ozet] },
    { oge: "span", cocuklar: [KART.durum] },
    { oge: "button", cocuklar: ["Ödünç al"] },
  ],
};

// C: gorsel, baslik ve "Ayrinti" ayri ayri baglanti
const C = {
  oge: "article",
  cocuklar: [
    { oge: "a", oz: { href: "/kayit/K-118" }, cocuklar: [{ oge: "img", oz: { alt: "" } }] },
    { oge: "h3", cocuklar: [{ oge: "a", oz: { href: "/kayit/K-118" }, cocuklar: [KART.baslik] }] },
    { oge: "p", cocuklar: [KART.yazar + ", " + KART.yil] },
    { oge: "span", cocuklar: [KART.durum] },
    { oge: "a", oz: { href: "/kayit/K-118" }, cocuklar: ["Ayrıntı"] },
    { oge: "button", cocuklar: ["Ödünç al"] },
  ],
};

const KALIPLAR = [
  ["A: kartin tamami baglanti", A],
  ["B: baslik baglanti + yayilan yuzey", B],
  ["C: her parca ayri baglanti", C],
];

const SAYFADAKI_KART = 40;

console.log("kalip".padEnd(36) + "durak".padEnd(8) + "40 kartta".padEnd(11) +
  "ic ice".padEnd(8) + "ilk duragin adi (karakter)");
for (const [baslik, k] of KALIPLAR) {
  const duraklar = odakDuraklari(k);
  const ilk = (k.cocuklar ?? []).flatMap(function bul(d) {
    if (typeof d === "string") return [];
    return etkilesimli(d) ? [d] : (d.cocuklar ?? []).flatMap(bul);
  })[0];
  const a = ad(ilk);
  console.log(baslik.padEnd(36) + String(duraklar.length).padEnd(8) +
    String(duraklar.length * SAYFADAKI_KART).padEnd(11) +
    String(icIce(k)).padEnd(8) + `"${a.slice(0, 34)}${a.length > 34 ? "…" : ""}" (${a.length})`);
}

console.log("\nsekme duraklari:");
for (const [baslik, k] of KALIPLAR) {
  console.log("  " + baslik);
  for (const d of odakDuraklari(k)) console.log("    " + d);
}

console.log("\nkural denetimi:");
let bulgu = 0;
for (const [baslik, k] of KALIPLAR) {
  const duraklar = odakDuraklari(k);
  const ogeler = (k.cocuklar ?? []).flatMap(function bul(d) {
    if (typeof d === "string") return [];
    return etkilesimli(d) ? [d, ...(d.cocuklar ?? []).flatMap(bul)] : (d.cocuklar ?? []).flatMap(bul);
  });
  const adlar = ogeler.map(ad);
  const b = [];
  if (icIce(k) > 0) b.push(`etkilesimli oge baska bir etkilesimli ogenin icinde (${icIce(k)} adet)`);
  for (const a of adlar) {
    if (a === "") b.push("adsiz durak: icerigi bos alternatif metinli gorsel");
    else if (a.length > 60) b.push(`erisilebilir ad ${a.length} karakter: gezinme listesinde okunamaz`);
  }
  const hedefler = new Map();
  for (const o of ogeler) {
    const h = o.oz?.href;
    if (!h) continue;
    if (!hedefler.has(h)) hedefler.set(h, new Set());
    hedefler.get(h).add(ad(o));
  }
  for (const [h, kume] of hedefler) {
    if (kume.size > 1) b.push(`ayni hedefe (${h}) farkli adlarla ${kume.size} baglanti gidiyor`);
  }
  if (duraklar.length * SAYFADAKI_KART > 100)
    b.push(`40 kartta ${duraklar.length * SAYFADAKI_KART} durak: liste sekme tusuyla gecilemez`);
  for (const x of b) { bulgu++; console.log("  " + baslik.padEnd(36) + x); }
}
console.log(`\n${KALIPLAR.length} kalipta ${bulgu} bulgu`);
```

```
kalip                               durak   40 kartta  ic ice  ilk duragin adi (karakter)
A: kartin tamami baglanti           2       80         1       "Yapıların Dili T. Aksoy, 2019 Yapı…" (96)
B: baslik baglanti + yayilan yuzey  2       80         0       "Yapıların Dili" (14)
C: her parca ayri baglanti          4       160        0       "" (0)

sekme duraklari:
  A: kartin tamami baglanti
    a[href]
    a > button
  B: baslik baglanti + yayilan yuzey
    a[href]
    button
  C: her parca ayri baglanti
    a[href]
    a[href]
    a[href]
    button

kural denetimi:
  A: kartin tamami baglanti           etkilesimli oge baska bir etkilesimli ogenin icinde (1 adet)
  A: kartin tamami baglanti           erisilebilir ad 96 karakter: gezinme listesinde okunamaz
  C: her parca ayri baglanti          adsiz durak: icerigi bos alternatif metinli gorsel
  C: her parca ayri baglanti          ayni hedefe (/kayit/K-118) farkli adlarla 3 baglanti gidiyor
  C: her parca ayri baglanti          40 kartta 160 durak: liste sekme tusuyla gecilemez

3 kalipta 5 bulgu
```

## Bulguların Okunması

**A kalıbı iki ayrı kural kırar.** Bağlantının içindeki düğme, ağaçta bir etkileşimli ögenin
içinde ikinci bir etkileşimli öge olarak durur; bu yerleşim tanımlı değildir ve
gerçekleştirimlerin nasıl davranacağı öngörülemez. İkincisi ölçülebilir: bağlantının adı
doksan altı karakter uzunluğunda. Kullanıcı bağlantı listesini açtığında her satır bir
paragraf uzunluğundadır ve liste taranamaz hâle gelir.

**C kalıbı sayıyla düşer.** Kart başına dört durak, kırk kartlık bir listede yüz altmış
durak eder. Klavyeyle gezen bir kullanıcının listeyi geçmesi yüz altmış sekme vuruşu
gerektirir. Aynı kalıp iki bulgu daha üretiyor: alternatif metni boş görselden oluşan
bağlantı adsız kalıyor ve aynı hedefe üç farklı adla üç bağlantı gidiyor.

**B kalıbı denetimden temiz çıkıyor.** Kart başına iki durak, tek ve kısa bir bağlantı adı,
iç içe yerleşim yok. Bunun bedeli sunum katmanındadır ve belirtimde yazılmalıdır: yayılan
yüzey kartın metnini fare ile seçilemez hâle getirir. Düzeltmesi, kaplamanın işaret
olaylarını yalnızca boş alanlarda yakalamasıdır.

Sekme durağı listesi bir ayrıntıyı daha gösteriyor. B ve C kalıplarında düğme kartın kendi
düzeyindedir; A kalıbında `a > button` yolunda, yani bağlantının içindedir. Yol bilgisi,
işaretlemeye bakmadan iç içe yerleşimi saptamanın yoludur.

## Klavye Sözleşmesi

Kartın kendi klavye sözleşmesi **yoktur**. Kart odak almaz, tuş dinlemez ve sekme sırasında
görünmez. Geçerli olan sözleşmeler, içindeki bağlantı ve düğmenin sözleşmeleridir.

Bu, belirtimin bir kararıdır: karta `tabindex` yazıp tıklama dinleyicisi bağlamak, sekme
durağı sayısını kart başına bir artırır ve odak alan bir kabuk üretir. O kabuğun rolü
yoktur, adı belirsizdir ve giriş tuşuna verdiği yanıt elle yazılmak zorundadır.

Kart listesi uzunsa sekme durağı sayısı ayrı bir kararla düşürülür: listeden önce bir atlama
bağlantısı konur ve kullanıcıya listeyi geçme yolu verilir. Kart içindeki ikincil denetimleri
gizleyip yalnız üzerine gelindiğinde göstermek bu sayıyı düşürmez, çünkü gizlenen denetim
klavyeyle ulaşılamaz hâle gelir.

## Ölçülebilir Kısıtlar

**2.4.7 Odak Görünürlüğü.** Kartın kenarında taşan içeriği kırpan bir sunum kararı, kart
kenarına yakın bir denetimin odak halkasını da kırpar. Gösterge var olur, görünmez.
Saptaması bir klavye turudur.

**1.4.11 Metin Dışı Kontrast.** Kartı sayfa yüzeyinden ayıran sınır, bilgi taşıyorsa 3:1
ölçüsüne girer. Kartlar birbirinden yalnız gölgeyle ayrılıyorsa ve gölge düşük karşıtlıksa,
grup sınırı görülemez.

**1.4.1 Rengin Tek Taşıyıcı Olmaması.** "Rafta", "Ödünçte", "Ayırtılmış" durum rozetleri
yalnız renkle ayrılamaz; her rozet metnini taşır.

**1.4.10 Yeniden Akış.** Kart ızgarası, 320 CSS pikseli genişliğe indirildiğinde iki yönlü
kaydırma gerektirmemelidir. Sabit genişlikli kart kutuları bu ölçütü doğrudan kaldırır.

**2.5.8 Hedef Boyutu.** Karttaki ikincil denetimler — işaretleme ve paylaşma düğmeleri — 24
piksel ölçüsüne ya da aralık istisnasına uymalıdır.

## Sık Yapılan Hata

**Kartın başlıksız bırakılması.** Kalın yazılmış bir metin başlık değildir. Saptaması, kart
listesindeki başlık düzeylerinin sayılmasıdır: kırk kart varsa ana hatta kırk başlık
bulunmalıdır.

**Görselin kayıt adıyla adlandırılması.** Kartın görseli, yanında zaten başlık dururken
alternatif metin taşırsa aynı bilgi iki kez duyurulur. Kararı: kart içindeki kapak görseli
sunumsaldır ve alternatif metni boştur.

**Kart listesinin liste olarak yazılmaması.** Saptaması, listenin ağaçtaki öge sayısının
ekrandaki kart sayısıyla karşılaştırılmasıdır; sayı yoksa yapı yoktur.

## Özet

- Kart bir denetim değil, türü farklı bilgileri tek birim olarak sunan bir gruplama
  düzenidir; türdeş ve karşılaştırılabilir veri için tablo kullanılır.
- Kart listesi liste ögeleriyle yazılır ve her kart bir başlık ögesi taşır; bu ikisi öge
  sayısını ve ana hattı ağaca bildirir.
- Kartın tamamını bağlantıya almak iç içe etkileşimli öge üretir ve bağlantı adını okunamaz
  uzunluğa çıkarır.
- Her parçayı ayrı bağlantı yapmak sekme durağı sayısını kart başına dörde çıkarır; kırk
  kartlık listede yüz altmış durak eder.
- Yalnız başlığın bağlantı olduğu ve yüzeyin ona yayıldığı kalıp üç ölçütten de temiz çıkar;
  bedeli metnin seçilebilirliğidir ve bu, kaplamanın olay yakalama alanıyla çözülür.
- Kartın kendi klavye sözleşmesi yoktur; karta odak vermek rolsüz ve adsız bir kabuk üretir.

## Sonraki Adım

Kart, içindeki denetimlerin toplamıydı; kendisi bir davranış taşımıyordu. Kayıt ayrıntısı
sayfasında ise durum değişir: künye, mevcut kopyalar ve ödünç geçmişi üç ayrı bölümdür ve
aynı anda yalnız biri gösterilir. Bu, kapsayıcının kendisinin bir davranış taşıdığı ilk
kalıptır — hangi bölümün görüneceğine o karar verir. Sonraki ders sekme kalıbını belirtir:
sekme başlıklarıyla panellerin nasıl ilişkilendirildiğini, dönen sekme durağının burada
neden zorunlu olduğunu ve seçimin kendiliğinden mi yoksa elle mi etkinleştirileceği
kararını ele alır.
