Yönlü Gezinme (Yön Tuş Takımı Odağı)

Web özellikleri: scrollIntoView()

Yön odaklı gezinme (ok tuşları veya d-pad'ler kullanılarak), yalnızca klavye ve alternatif giriş kullanan kullanıcıların etkileşimli öğelerde görsel 2D düzenlerine göre gezinmesine olanak tanır. Bu özellik, uzamsal kullanıcı arayüzleri (ör. medya şeritleri, kontrol panelleri veya iç içe yerleştirilmiş kataloglar) için son derece faydalıdır ancak görüntü alanını kaydırma gibi yerel tarayıcı davranışlarını bozmamak için dikkatli bir şekilde uygulanmalıdır.

Bu kılavuzda, bileşik widget'larda yüksek performanslı ve erişilebilir 2D yönlü gezinme oluşturma konusu ele alınmaktadır.


Temel Mimari İlkeler

Özel ok tuşu uzamsal odağını uygularken aşağıdaki temel kurallara uyun:

  1. Bileşik widget'larla sınırlayın: Normal belge metin akışında veya varsayılan sıralı sekme gezinmesinin beklendiği basit dikey liste düzenlerinde ok tuşlarını geçersiz kılmayın. Genel doküman akışı kılavuzu için Erişilebilirlik Kodlama Kuralları'na bakın.
  2. Doğal sınır kaydırmayı koruyun: Basılan yönde odaklanılabilir öğe yoksa varsayılan tarayıcı davranışını engellemeyin. Tarayıcının görüntü alanını yerel olarak kaydırabilmesi için etkinliğin kabarmasına izin verin. Ok tuşlarını geçersiz kılmak, erişilebilirliği koşulsuz olarak bozar (WCAG 1.4.10).
  3. Odak görünürlüğünü ve hizalamasını sağlayın: Odak değiştiğinde, yeni odaklanan öğenin tamamen görünür kalması için kaydırılarak görünür hale getirildiğinden (ör. scrollIntoView({ block: 'nearest', inline: 'nearest' }) kullanarak) emin olun.
  4. Düzen sistemiyle koordinasyon: Her tuş basımını işlerken canlı sınırlayıcı geometrilerden (getBoundingClientRect()) odak adayı konumlarını belirleyin. DOM sırasının veya sabit bir ızgara yapısının görsel düzeni temsil ettiğini varsaymayın. Modern düzen önerileri için CSS Düzenleri ve Duyarlı Tasarım başlıklı makaleyi inceleyin.

Erişilebilir Odak Yönetimi

Uzamsal kapsayıcı, sıralı sayfa sekmesi gezinmesi için tek bir sekme durağı göstermelidir. Widget'ın içinde, Roving Tabindex Pattern'i kullanarak klavye odağını yönetin:

  • Etkin öğede tabindex="0" var.
  • Etkin olmayan tüm öğelerde tabindex="-1" var.
  • Gezinirken tabindex="0" özelliğini değiştirip focus() yöntemini çağırarak odağı programatik olarak taşıyın.

Görsel Aday Seçimi

Asimetrik, sarmalanmış veya ızgara düzenlerinde dizine dayalı eşleme başarısız olur. Bunun yerine, mevcut tuş basımı için canlı görsel geometriden adaylar türetin:

  • Adaylar: Widget kapsayıcısının checkVisibility() değerini geçen odaklanılabilir alt öğelerini kullanın. Gizli öğeler, (0, 0) konumunda sıfır boyutlu bir dikdörtgene sahip olabilir ve yanlışlıkla up veya left hedefi olmamalıdır.
  • Geometri: Tuş basımını işlerken odaklanılan öğe ve her aday için getBoundingClientRect() değerini okuyun. Bu dikdörtgenleri genel olarak önbelleğe almayın: Düzen birçok nedenden dolayı değişebilir ve kullanıcı hızında bir tuş etkinliği işlenirken az sayıda geometri okuması ucuzdur.
  • Yön filtresi: Bir aday, yalnızca yakın kenarı o eksendeki mevcut öğenin uzak kenarında veya ötesinde olduğunda basılı yöndedir. Bu, alt piksel yuvarlama için küçük bir tolerans sağlar. Örneğin, right için bir adayın candidate.left >= current.right - tolerance olması gerekir. Bir adayın yön içinde olup olmadığını belirlemek için merkezleri karşılaştırmayın.
  • Önce hizalanmış adaylar: Yön filtresini geçen adaylar arasından, dikey eksendeki kapsamı mevcut öğenin kapsamıyla çakışan adayları tercih edin. Gezinme eksenindeki en küçük boşluğu seçin ve en küçük dikey merkez ofsetiyle bağları koparın. Bu sayede, bir öğe alışılmadık derecede geniş olsa bile gezinme bitişik görsel satırda veya sütunda kalır.
  • Yedek puanlama: Dikey eksende çakışan aday yoksa kalan adayları gap + w * perpendicularCentreOffset olarak puanlayın ve minimum değeri seçin. Başlangıç noktası olarak w >= 2 ağırlığını kullanın, ardından düzene göre ayarlayın. Daha büyük bir ağırlık, daha yakın hizalanmış adayları tercih eder.
  • Aday yok: Hiçbir şey döndürmez. Etkinlik işleyici, preventDefault() yöntemini çağırmamalı ve tarayıcının yerel olarak kaydırma yapmasına izin vermelidir.

Tam uygulama değişiklik gösterebilir ancak yön testini kenar tabanlı tutun ve ağırlıklı yedeklemeden önce çakışma tercihini uygulayın. Bu, algoritmanın en önemli noktasıdır. Önbelleği veya sabit bir ağırlığı her zaman doğruymuş gibi sunmaktan kaçının.


Tuş Basma Entegrasyonu ve Kaydırma İşbirliği

Etkinlik yönlendiriciniz, yalnızca geçerli bir uzamsal odak geçişi gerçekleştiğinde standart görüntü alanı kaydırmayı engellemelidir:

  • Bir değiştirici tuş basılı tutulduğunda, e.defaultPrevented zaten doğru olduğunda veya en içteki etkinlik hedefi ok tuşlarını kendisi kullandığında etkinliği kesmeyin. Yalnızca e.target yerine e.composedPath()[0] kullanın. e.target, gölge ana makineye yeniden hedeflenebilir. Pratik bir düzenlenebilir/kontrol denetimi target.matches(':read-write, select, input[type="range"], [role="slider"]'); kapalı gölge kökleri incelenemez.
  • Dinleyiciyi widget kapsayıcısıyla sınırlayın. Böylece, bir sayfada birden fazla uzamsal widget bulunabilir.
  • Yalnızca odaklanılan öğe bir aday olduğunda işlem yapın. Öğeler kendi odaklanabilir denetimlerini içeriyorsa bu denetimleri de aday yapın veya olduğu gibi bırakın. closest() ile bir üst öğeyi çözümlemeyin.
  • Bir aday bulunduğunda preventDefault() işlevini çağırın, gezici tabindex değerini güncelleyin, focus() işlevini çağırın ve scrollIntoView({ block: 'nearest', inline: 'nearest' }) değerini kullanın.
  • Aday bulunamazsa preventDefault() çağrılmadan döndürülür ve yerel kaydırma devam eder.

Yön tuşlarıyla gezinme için h/j/k/l veya W/A/S/D gibi tek karakterli kısayollar eklemeyin. Ok tuşları karakter tuşları değildir ve aday olmadığında yerel kaydırmanın korunması, görüntü alanı hareketinin gereksiz yere engellenmesini önler.