مشکل
برای منوهای کرکرهای اجباری (مثلاً «انتخاب کشور»)، اگر گزینه پیشفرض مقدار خالی داشته باشد، اعتبارسنجی استاندارد فوراً فیلد را بهعنوان نامعتبر پرچمگذاری میکند. این کار میتواند نویز بصری ایجاد کند. میخواهیم خطا را فقط زمانی نشان دهیم که کاربر منو را باز میکند و بدون انتخاب گزینهای آن را میبندد، یا تلاش میکند فرم را ارسال کند.
راهحل
کلاس کاذب :user-invalid بهطور یکپارچه با عناصر <select> کار میکند. این ویژگی به جریان تعامل کاربر احترام میگذارد: صرفاً بار کردن صفحه یا تمرکز/محو کردن بدون ایجاد تغییر بهعنوان تعامل محسوب نمیشود، بنابراین فیلد تا زمانی که کاربر فعالانه برای انتخاب تلاش نکند، خنثی میماند.
راهبرد پیادهسازی
- محدودیت HTML: از
<select>باrequiredاستفاده کنید. گزینه اول بایدvalue=""داشته باشد و در حالت ایدهآل غیرفعال/ پنهان باشد تا انتخاب معتبری را اجبار کند. - بازخورد دیداری: از
:user-invalidبرای سبکدهی به حاشیه چارگوش انتخاب استفاده کنید. - زمانبندی: اگر کاربر مقدار را قبلاز محو کردن کنترل یا هنگام ارسال فرم تغییر دهد (حتی اگر به حالت نامعتبر پیشفرض برگردد)، مرورگر فیلد را «تعاملشده» درنظر میگیرد.
راهنمای پیادهسازی
۱. ساختار HTML
گزینه «جایبان» در اینجا کلیدی است.
<form>
<div class="field">
<label for="country">Country</label>
<select
id="country"
name="country"
required
aria-errormessage="country-error"
>
<option value="" disabled selected>Select a country...</option>
<option value="us">United States</option>
<option value="ca">Canada</option>
<option value="uk">United Kingdom</option>
</select>
<div id="country-error" class="error-msg">
Please select a country.
</div>
</div>
</form>
۲. CSS
.error-msg {
display: none;
color: #d93025;
font-size: 0.875rem;
margin-top: 0.25rem;
}
/*
Only show error after the user visits the select menu.
*/
select:user-invalid {
border-color: #d93025;
background-color: #fce8e6;
}
select:user-invalid + .error-msg {
display: block;
}
select:user-valid {
border-color: #188038;
}
پشتیبانی از مرورگر و بازگشت به حالت قبلی
پشتیبانی مرورگر و بازگشت برای :user-valid و :user-invalid
CSS برای گزینه جایگزین
input:user-invalid,
input.user-invalid-fallback {
border-color: #d93025;
background-color: #fce8e6;
}
input:user-invalid + .error-msg,
input.user-invalid-fallback + .error-msg {
display: block;
}
بازگشت جاوا اسکریپت
از ابزار کمکی قابلاستفاده مجددی استفاده کنید که وضعیت تعامل را بااستفاده از WeakMap ردیابی میکند. این کار از آلوده شدن DOM با کلاسهای «کثیف» یا مشخصههای داده جلوگیری میکند.
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') {
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.checkValidity) 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 = (root = document) => {
if (CSS.supports('selector(:user-invalid)')) return;
root.addEventListener('blur', handleEvent, true); // Capture phase
root.addEventListener('input', handleEvent);
root.addEventListener('change', handleEvent);
root.addEventListener('reset', handleEvent, true); // Capture resets
};
return { init };
})();
// Initialize for a specific form
const form = document.querySelector('#demo-form');
UserInvalidFallback.init(form);
ملاحظات دیگر
- رفتار در تلفن همراه: در دستگاههای همراه، «محو کردن» ممکن است بسته به انتخابگر سیستمعامل متفاوت باشد. آزمایش کردن روی دستگاههای واقعی توصیه میشود.
- دسترسپذیری:
:user-invalidبومی بهطور خودکار با شاخصههای ARIA همگامسازی نمیشود. برای همگام نگه داشتنaria-invalidبا وضعیت دیداری، جاوا اسکریپت زیر را اضافه کنید:
// Sync aria-invalid with the CSS :user-invalid state
const syncAria = (el) => {
el.setAttribute?.('aria-invalid', el.matches(':user-invalid') ? 'true' : 'false');
};
// Update on blur (to show error) and input (to clear it)
document.addEventListener('blur', (e) => syncAria(e.target), true);
document.addEventListener('input', (e) => {
if (e.target.hasAttribute('aria-invalid')) syncAria(e.target);
});