Sorun
Standart HTML5 doğrulaması, görsel geri bildirim (:invalid veya :user-invalid aracılığıyla) sağlar ancak aria-invalid gibi erişilebilirlik özellikleriyle otomatik olarak senkronize edilmez.
Standart :invalid stilini kullanırsanız ekran okuyucular, kullanıcı boş bir zorunlu alana sekme tuşuyla geçtiği anda "Geçersiz giriş" uyarısı verebilir. Hata, etkileşim gerçekleşmeden önce duyurulduğu için yardımcı teknolojileri kullanan kullanıcılar açısından rahatsız edici bir deneyim oluşturur.
Çözüm
Programatik durumun (aria-invalid="true"), görsel durumun (:user-invalid) uygulandığı anda uygulanmasını istiyoruz. :user-invalid, tarayıcının dahili "kullanıcı etkileşimli " işaretine dayandığından, standart etkileşim etkinlikleri sırasında bu seçicinin eşleştiğini kontrol etmek için JavaScript'i kullanabiliriz.
Daha fazla bilgi için MDN aria-invalid sayfasına bakın.
Uygulama Stratejisi
- Görsel Katman: Kenarlıkları/simgeleri göstermek için CSS
:user-invalidkullanın. - Erişilebilirlik Katmanı: Durumu Yardımcı Teknoloji'ye (AT) iletmek için
aria-invalidvearia-errormessagekullanın. - Görsel ve Erişilebilirlik Katmanını Birleştirme:
blurveinputetkinliklerini dinleyen, öğenin:user-invalidile eşleşip eşleşmediğini kontrol eden ve ARIA özelliklerini buna göre güncelleyen basit bir JavaScript yardımcı programı oluşturun.
Uygulama Kılavuzu
1. HTML Yapısı
aria-errormessage (veya daha geniş destek için aria-describedby) kullanarak girişinizi hata mesajına bağlayın.
<form>
<div class="field">
<label for="email">Email</label>
<input
type="email"
id="email"
required
aria-errormessage="email-error"
>
<span id="email-error" class="error-msg">
Please enter a valid email address.
</span>
</div>
</form>
2. CSS
Yerel sözde sınıf :user-invalid kullanarak hata mesajının görünürlüğünü kontrol edin.
.error-msg {
display: none;
color: #d93025;
}
/* Show error message when input is user-invalid */
input:user-invalid ~ .error-msg {
display: block;
}
/* Optional: Visual cues on the input itself */
input:user-invalid {
border-color: #d93025;
}
3. JavaScript
"UserInvalidChanged" etkinliği olmadığından, durumu kontrol etmek için standart form etkinliklerini kullanın.
const updateAriaState = (event) => {
const input = event.target;
if (!input.matches?.('input, textarea, select')) return;
// Check if the browser currently considers this input "user-invalid"
const isUserInvalid = input.matches(':user-invalid');
if (isUserInvalid) {
input.setAttribute('aria-invalid', 'true');
} else {
input.removeAttribute('aria-invalid');
}
};
// Listen on the document to handle dynamically added fields.
// 'blur' and 'focus' do not bubble, so we must use the capture phase (true).
document.addEventListener('blur', updateAriaState, true);
document.addEventListener('focus', updateAriaState, true);
// Also update on input if we've already shown the error,
// so the error clears immediately when fixed.
document.addEventListener('input', (event) => {
const input = event.target;
if (!input.matches?.('input, textarea, select')) return;
const hasAriaInvalid = input.hasAttribute('aria-invalid');
const ariaInvalid = input.getAttribute('aria-invalid');
if (hasAriaInvalid && ariaInvalid === 'true') {
updateAriaState(event);
}
});
Yedekleme ve Tarayıcı Desteği
Özellik Algılama
CSS ve JavaScript'te destek olup olmadığını kontrol edebilirsiniz.
JavaScript Kontrolü:
if (!CSS.supports('selector(:user-invalid)')) {
// Fallback logic here
}
Yedek için CSS
Yedek mantığınızın yerel davranıştan görsel olarak ayırt edilemediğinden emin olmak için hata stillerinizi hem sözde sınıfa hem de yedek sınıfınıza uygulamanız gerekir.
/* Apply error styles to both native selector and fallback class */
input:user-invalid,
input.user-invalid-fallback {
border-color: #d93025;
background-color: #fce8e6;
}
/* Show error message for both cases */
input:user-invalid ~ .error-msg,
input.user-invalid-fallback ~ .error-msg {
display: block;
}
Yedek Mantık
:user-invalid eksikse WeakMap kullanarak etkileşim durumunu manuel olarak izleyin.
const UserInvalidFallback = (() => {
const dirtyState = new WeakMap();
const updateState = (input) => {
const isValid = input.checkValidity();
// Update both visual and ARIA state
input.classList.toggle('user-invalid-fallback', !isValid);
input.classList.toggle('user-valid-fallback', isValid);
if (!isValid) {
input.setAttribute('aria-invalid', 'true');
} else {
input.removeAttribute('aria-invalid');
}
};
const handleEvent = (event) => {
const input = event.target;
if (event.type === 'reset' && input.matches?.('form')) {
const controls = input.elements || [];
for (const control of controls) {
dirtyState.delete(control);
control.classList.remove('user-invalid-fallback');
control.classList.remove('user-valid-fallback');
control.removeAttribute('aria-invalid');
}
return;
}
if (!input.matches?.('input, textarea, select')) return;
if (event.type === 'input' || event.type === 'change') {
const state = dirtyState.get(input) || { hasInteracted: false, hasBlurred: false };
state.hasInteracted = true;
dirtyState.set(input, state);
if (state.hasBlurred) {
updateState(input);
}
} else if (event.type === 'blur') {
const state = dirtyState.get(input) || { hasInteracted: false, hasBlurred: false };
state.hasBlurred = true;
dirtyState.set(input, state);
if (state.hasInteracted) {
updateState(input);
}
}
};
const init = () => {
if (CSS.supports('selector(:user-invalid)')) return;
document.addEventListener('blur', handleEvent, true); // Capture phase required
document.addEventListener('input', handleEvent, true);
document.addEventListener('change', handleEvent, true);
document.addEventListener('reset', handleEvent, true); // Capture resets
};
return { init };
})();
// Initialize globally
UserInvalidFallback.init();
Dikkat edilmesi gereken diğer noktalar
aria-livevearia-errormessage:aria-errormessage, girişi metne bağlar ancak ekran okuyucular, giriş göründüğünde bunu hemen duyurmayabilir (yalnızca girişe odaklanıldığında).- Hata göründüğünde (ör.bulanıklaştırmada) hemen duyuru yapılması gerekiyorsa hata mesajı kapsayıcısına
role="alert"veyaaria-live="polite"ekleyebilirsiniz. Ancak kullanıcı düzeltmek için alana odaklandığında "çift duyuru" yapılmasını önlemek için kapsamlı bir şekilde test edin.
Uluslararasılaştırma:
- Hata mesajınızın (
#email-error) metin içeriğinin çevrildiğinden emin olun. Mantık aynıdır.
- Hata mesajınızın (