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:
- 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.
- 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).
- 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. - 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ştiripfocus()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ıklaupveyalefthedefi 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,
rightiçin bir adayıncandidate.left >= current.right - toleranceolması 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 * perpendicularCentreOffsetolarak puanlayın ve minimum değeri seçin. Başlangıç noktası olarakw >= 2ağı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.defaultPreventedzaten doğru olduğunda veya en içteki etkinlik hedefi ok tuşlarını kendisi kullandığında etkinliği kesmeyin. Yalnızcae.targetyerinee.composedPath()[0]kullanın.e.target, gölge ana makineye yeniden hedeflenebilir. Pratik bir düzenlenebilir/kontrol denetimitarget.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, gezicitabindexdeğerini güncelleyin,focus()işlevini çağırın vescrollIntoView({ 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.