---
title: 'Erişilebilir Hareket'
source: 'https://academia.sh/tr/kurslar/duzen-ve-duyarli-tasarim/erisilebilir-hareket'
course: 'Düzen Sistemleri ve Duyarlı Tasarım'
language: tr
updated: '2026-08-17T18:09:26+00:00'
license: 'CC BY-SA 4.0'
---

# Erişilebilir Hareket

Hareket duyarlılığının ne olduğu, büyük alanlı hareketin yerel hareketten ayrılması, hareket azaltma tercihinde toptan kapatmanın bedeli ve hareketi kaldırmak yerine değiştirmenin kuralları.

Önceki ders hareketin tarayıcıya maliyetini ele aldı. Bir maliyet daha vardır ve o
tarayıcıya değil kullanıcıya çıkar: ekrandaki hareket bazı kullanıcılarda baş dönmesi,
bulantı ya da odaklanma güçlüğü üretir.

Duyarlı Tasarım konusunda `prefers-reduced-motion` sorgusu tanıtıldı ve kullanıcının bu
tercihi işletim sisteminden bildirdiği gösterildi. Bu ders sorgunun içine ne yazılacağını
ele alır: hangi hareket kaldırılır, hangisi korunur ve toptan kapatmanın bedeli nedir?

## Hareket Duyarlılığı Neye Tepki Verir

Hareket duyarlılığı, iç kulaktaki denge düzeneğiyle görsel algının uyuşmamasından doğar.
Ekranda büyük bir alan hareket ettiğinde görsel sistem kendi hareketimiz olduğu izlenimini
üretir; denge düzeneği bunu doğrulamaz ve uyuşmazlık rahatsızlık verir.

Tetikleyen hareket türleri belirlidir: geniş alanların kayması, farklı hızlarda kayan
katmanlar, yakınlaşma ve uzaklaşma, dönme, salınım. Tetiklemeyenler de belirlidir:
saydamlık değişimi, renk değişimi, küçük alanlı yer değiştirme.

Ayrım "animasyon var mı yok mu" değildir. Ayrım, hareketin **ne kadar alanı ne kadar yol
boyunca** taşıdığıdır.

## Basamaklama ve Alan Hesabı

Aşağıdaki program iki şeyi hesaplıyor. Birincisi, hareket azaltma tercihinin iki durumu için
kazanan bildirimleri basamaklama kurallarıyla çözüyor. İkincisi, dört hareketi kapladıkları
alan ve kat ettikleri yola göre sınıflandırıyor.

```js
// hareketazalt.mjs — tercih altinda basamaklama cozumu ve hareketin ekranda kapladigi alan
// Basamaklama: once onem, sonra ozgulluk ucluleri, sonra yazim sirasi.
const KURALLAR = [
  { sira: 1, secici: ".gosterge",  ozgulluk: [0, 1, 0], kosul: null,           bildirim: { "animation-name": "nabiz", "animation-duration": "1400ms" } },
  { sira: 2, secici: ".kart",      ozgulluk: [0, 1, 0], kosul: null,           bildirim: { "transition-duration": "240ms" } },
  { sira: 3, secici: "*",          ozgulluk: [0, 0, 0], kosul: "reduce",       bildirim: { "animation-duration": "0.01ms", "transition-duration": "0.01ms" }, onemli: true },
  { sira: 4, secici: ".gosterge",  ozgulluk: [0, 1, 0], kosul: "reduce",       bildirim: { "animation-name": "none" } },
];

const uygular = (kural, tercih) => kural.kosul === null || kural.kosul === tercih;
const buyuk = (a, b) => {                       // ozgulluk uclulerinin karsilastirmasi
  for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return a[i] > b[i];
  return false;
};

function coz(tercih, ozellikler) {
  const sonuc = {};
  for (const ozellik of ozellikler) {
    let kazanan = null;
    for (const k of KURALLAR) {
      if (!uygular(k, tercih) || !(ozellik in k.bildirim)) continue;
      if (kazanan === null) { kazanan = k; continue; }
      const kOnem = !!k.onemli, zOnem = !!kazanan.onemli;
      if (kOnem !== zOnem) { if (kOnem) kazanan = k; continue; }
      if (buyuk(k.ozgulluk, kazanan.ozgulluk)) { kazanan = k; continue; }
      if (!buyuk(kazanan.ozgulluk, k.ozgulluk) && k.sira > kazanan.sira) kazanan = k;
    }
    sonuc[ozellik] = kazanan ? `${kazanan.bildirim[ozellik]}   (kural ${kazanan.sira}: ${kazanan.secici}${kazanan.onemli ? " !important" : ""})` : "bildirim yok";
  }
  return sonuc;
}

const OZELLIKLER = ["animation-name", "animation-duration", "transition-duration"];
for (const tercih of ["no-preference", "reduce"]) {
  console.log(`\n=== prefers-reduced-motion: ${tercih} ===`);
  const s = coz(tercih, OZELLIKLER);
  for (const o of OZELLIKLER) console.log(`  ${o.padEnd(20)} -> ${s[o]}`);
}

// --- hareketin ekranda kapladigi oran ---
// Buyuk alanli ve uzun yollu hareket, hareket duyarliligi olan kullanicilar icin
// kucuk alanli hareketten farkli bir sinifta degerlendirilir.
console.log("\n--- hareketin goruntu alanina orani (1280 x 800 birim) ---");
const EN = 1280, BOY = 800;
const HAREKETLER = [
  { ad: "kart vurgusu",       en: 220, boy: 120, yol: 8 },
  { ad: "gosterge nabzi",     en: 12,  boy: 12,  yol: 1 },
  { ad: "yan panel acilisi",  en: 320, boy: 800, yol: 320 },
  { ad: "arka plan kaymasi",  en: 1280, boy: 800, yol: 240 },
];
console.log("hareket".padEnd(20) + "alan orani".padStart(12) + "yol / ekran".padStart(14) + "  siniflandirma");
for (const h of HAREKETLER) {
  const alan = (h.en * h.boy) / (EN * BOY);
  const yol = h.yol / Math.max(EN, BOY);
  const buyukAlan = alan >= 0.25 && yol >= 0.05;
  console.log(
    h.ad.padEnd(20) +
    `%${(alan * 100).toFixed(1)}`.padStart(12) +
    `%${(yol * 100).toFixed(1)}`.padStart(14) +
    "  " + (buyukAlan ? "buyuk alanli hareket" : "yerel hareket"),
  );
}
```

```

=== prefers-reduced-motion: no-preference ===
  animation-name       -> nabiz   (kural 1: .gosterge)
  animation-duration   -> 1400ms   (kural 1: .gosterge)
  transition-duration  -> 240ms   (kural 2: .kart)

=== prefers-reduced-motion: reduce ===
  animation-name       -> none   (kural 4: .gosterge)
  animation-duration   -> 0.01ms   (kural 3: * !important)
  transition-duration  -> 0.01ms   (kural 3: * !important)

--- hareketin goruntu alanina orani (1280 x 800 birim) ---
hareket               alan orani   yol / ekran  siniflandirma
kart vurgusu                %2.6          %0.6  yerel hareket
gosterge nabzi              %0.0          %0.1  yerel hareket
yan panel acilisi          %25.0         %25.0  buyuk alanli hareket
arka plan kaymasi         %100.0         %18.8  buyuk alanli hareket
```

İkinci blok bir ayıklama ölçütü veriyor. Kart vurgusu görüntü alanının yüzde üçünden azını
kaplıyor ve sekiz birim yol alıyor; gösterge nabzı daha da küçük. Yan panel görüntü alanının
dörtte birini kaplıyor ve genişliği kadar yol alıyor; arka plan kayması bütün ekranı
kaplıyor.

Eşikler kesin sayılar değil, ayıklama araçlarıdır: kaplanan alan ile kat edilen yolun
ikisinin de büyük olduğu hareketler ayrı bir sınıfa konur. Bu sınıftaki hareketler, tercih
bildirildiğinde kaldırılır; yerel hareketler kısaltılarak korunabilir.

## Toptan Kapatmanın Bedeli

İlk blok, sık yazılan bir kalıbı çözümlüyor: evrensel seçiciye `!important` ile sıfıra yakın
süre yazan bir kural. Sonuç okunduğunda kuralın gücü görünüyor — üçüncü kural, kendisinden
daha özgül olan birinci kuralın süresini de bastırıyor.

Süre neden $0$ değil de $0{,}01$ milisaniye? Sıfır süreli bir geçiş hiç çalışmaz ve bitiş
olayı da yayılmaz; hareketin bitmesini bekleyen betikler o olayı hiç almaz. Çok kısa ama
sıfırdan büyük bir süre, hareketi görünmez kılarken olay zincirini korur.

Kalıbın bedeli, ayrım yapmamasıdır. Aynı kural şunları da bastırır:

- Bir formun hata iletisinin yumuşak belirmesi — hareket değil, dikkat yönlendirmesidir.
- Bir açılır menünün kapanışı — anlık kapanma, ögenin nereye gittiğini gizler.
- Yükleniyor göstergesinin dönmesi — durum bilgisi taşır; kaldırılırsa yerine yazı konmalıdır.

Toptan kapatma bir başlangıç noktası olarak yazılabilir, ama bileşen bileşen gözden
geçirilmemişse yarım bir çözümdür. Dördüncü kuralın yaptığı budur: göstergenin animasyonunu
adıyla kapatır, yerine başka bir bildirim koyma sorumluluğunu üstlenir.

## Kaldırmak Değil, Değiştirmek

Hareket azaltma tercihi "hiç animasyon istemiyorum" demek değildir; büyük alanlı ve yol
kateden hareketin azaltılmasını ister. Bu, hareketle taşınan bilgiyi de silmek anlamına
gelmez.

Üç kural yeterlidir:

1. **Yer değiştirmeyi saydamlıkla değiştir.** Kayarak giren bir panel, yerinde belirebilir.
   Bilgi korunur, yol ortadan kalkar.
2. **Süreyi kısalt, döngüyü kaldır.** Sonsuz yinelenen bir hareket, tercihte tek turluk bir
   duruma indirilir ya da durur.
3. **Durum taşıyan hareketin yerine yazı koy.** Dönen bir gösterge yerine "veri bekleniyor"
   metni aynı bilgiyi taşır ve hiç hareket etmez.

Kayan yazı, otomatik ilerleyen tanıtım şeritleri ve arka plan videoları ayrı bir başlıktır.
Erişilebilirlik ölçütlerinden 2.2.2, beş saniyeden uzun süren, kendiliğinden başlayan
hareketin durdurulabilir olmasını ister; 2.3.1 saniyede üçten fazla parlamayı yasaklar;
2.3.3 ise etkileşimle tetiklenen hareketin kapatılabilmesini ister. İlk ikisi tercih
bildirilmemiş olsa bile geçerlidir.

## Yazım Yönü Seçimi

İki yazım yönü vardır. Birincisi hareketi varsayılan yazar ve `reduce` sorgusunda kapatır.
İkincisi hareketsiz yazar ve `no-preference` sorgusunda açar.

İkincisinin bir üstünlüğü vardır: sorgu değerlendirilemediğinde koşul sağlanmaz ve hareket
açılmaz. Yani belirsizlik hareketsizlik lehine çözülür. Birinci yönde belirsizlik hareket
lehine çözülür.

Bedeli, hareketin varsayılan durumdan ayrı bir yere yazılmasıdır; bileşenin biçemi iki
parçaya bölünür. Seçim, hareketin sayfadaki ağırlığına göre yapılır: sayfa boyunca birkaç
küçük geçiş varsa birinci yön yeterlidir, hareket tasarımın merkezindeyse ikinci yön
güvenlidir.

## İstasyon Sayfasında

```css
/* hareket.css — 5. adım: hareket azaltma tercihi */
@media (prefers-reduced-motion: reduce) {
  .olcum-kartlari > .kart {
    transition-duration: 80ms;
  }

  .olcum-kartlari > .kart:hover,
  .olcum-kartlari > .kart:focus-within {
    transform: none;
    box-shadow: 0 0 0 2px var(--marka-koyu);
  }

  .istasyon-durumu[data-durum="bekliyor"] .gosterge {
    animation: none;
    will-change: auto;
  }

  .yan-bilgi {
    scroll-behavior: auto;
  }
}
```

Kart vurgusu kaldırılmadı, **değiştirildi**: yükselme ve büyüme yerine bir çerçeve geliyor.
Kullanıcı hangi kartın vurgulandığını yine görüyor, kart yer değiştirmiyor. Süre kısaltıldı
ama sıfırlanmadı; ani değişim de rahatsız edicidir.

Gösterge animasyonu kapatıldı ve katman ipucu geri alındı. Durum bilgisinin yazıyla da
verilmesi gerekir; bu, biçem dosyasının değil belgenin sorumluluğudur ve `.gosterge`
ögesinin yanındaki metin bunu üstlenir.

`scroll-behavior: auto` bildirimi, yumuşak kaydırmayı ani kaydırmaya çevirir. Kaydırma tüm
görüntü alanını hareket ettirdiği için büyük alanlı hareket sınıfındadır.

## Özet

- Hareket duyarlılığı, görsel algı ile denge düzeneğinin uyuşmamasından doğar; tetikleyen
  şey animasyonun varlığı değil, kaplanan alan ile kat edilen yolun büyüklüğüdür.
- Kaplanan alan ve yol oranı hesaplanarak hareketler ayıklanır: büyük alanlı olanlar
  kaldırılır, yerel olanlar kısaltılarak korunabilir.
- Evrensel seçiciye yazılan `!important` süre kuralı bütün bildirimleri bastırır; bitiş
  olaylarının yayılması için süre sıfır değil sıfıra yakın yazılır.
- Hareket kaldırılırken taşıdığı bilgi kaldırılmaz: yer değiştirme saydamlığa çevrilir,
  döngü durdurulur, durum taşıyan hareketin yerine yazı konur.
- Hareketi varsayılan yazıp kapatmakla, hareketsiz yazıp açmak arasındaki seçim,
  belirsizliğin hangi yöne çözüleceğini belirler.

## Sonraki Adım

Bu konu boyunca `hareket.css` adında üçüncü bir biçem dosyası büyüdü. Artık aynı ögeye üç
ayrı dosyadan bildirim geliyor: görsel bildirimler `istasyon.css` dosyasında, yerleşim
`duzen.css` dosyasında, hareket burada. Sınıf adları da çoğaldı ve hangi adın hangi
bileşene ait olduğu yalnız alışkanlıkla biliniyor. Sonraki konu bu düzensizliği bir soruya
çevirir: biçem katmanı hangi kurallarla adlandırılır ve bölünür ki büyüdükçe okunur kalsın?
