Затримка HTML5: неприпустимий псевдо-клас до першої події

Нещодавно я виявив, що псевдо-клас : invalid застосовується до елементів форми required , як тільки сторінка завантажується. Наприклад, якщо у вас є цей код:

…
<input name="foo" required />

Тоді ваша сторінка буде завантажуватися з порожнім рожевим вхідним елементом. Вбудована перевірка HTML5 є великою, але я не думаю, що більшість користувачів очікують, що форма перевірятиметься до того, як вони взагалі матимуть змогу ввести будь-які значення. Чи є спосіб затримати застосування псевдо-класу до першої події, що впливає на цей елемент (форма подання, розмиття, зміна, незалежно від того, що доречно)? Чи можна це зробити без JavaScript?

48
Я не можу коментувати, тому я додаю цю додатку до @ user3284463. ) {if (! e.target.classList.contains ('dirty')) e.target.classList.add ('брудний'); }
додано Автор Abir Stolov, джерело

9 Відповіді

http://www.alistapart.com/articles/forward-thinking-form-validation/

Оскільки ми хочемо лише позначати, що поле є недійсним, як тільки воно має   фокус, ми використовуємо фокус псевдо-клас для ініціювання недійсного стилю.   (Звичайно, позначте всі необхідні поля недійсними з самого початку   було б поганим вибором дизайну.)

Після цієї логіки ваш код виглядатиме приблизно так:

32
додано
Я можу уявити (не-існуючий) pseduo-клас для форм, як "подано", так що це буде діяти як батьківський селектор для будь-яких міститься вхідних даних, наприклад, #myform: поданий вхід: обов'язковий: недійсний . Тому що навіть якщо цей поточний сценарій дійсно неінтуїтивний, не обов'язково реалістично очікувати, що CSS дізнається, що поле є недійсним за певних обставин (чому він не повинен робити це відразу, наскільки це відомо?) Ви дійсно бажаєте прив'язати стиль введення до стану форми, а не сам вхід (наприклад, коли обов'язкове поле порожнє І подається батьківська форма).
додано Автор Anthony, джерело
Ця відповідь: stackoverflow.com/questions/41619497/… насправді має справу з цим добре, я думаю, навіть якщо це вимагає трохи javascript. Він просто додає клас "поданий" до форми (так само, як я пропонував!), Щоб правила стилю могли бути form.submitted input: required: недійсним
додано Автор Anthony, джерело
Крім того, щоб повністю вичерпати цю точку, одна й та ж проблема має бути з іншими типами вводу : valid або : . Якщо ввести тип integer і ніщо не заповнено, то воно повинно відображатися як недійсне, оскільки порожнє не є дійсним числовим значенням. Єдина причина, чому це не є проблемою, тому, що поза властивістю required , порожнє значення вважається дійсним значенням.
додано Автор Anthony, джерело
"Не ідеально будь-якими засобами". Дійсно. Чи є спосіб застосування стилів до дійсного, але не необхідного вмісту, після того, як елемент втратив фокус? Я не вирішив цього зробити.
додано Автор Donald Jenkins, джерело

Це неможливо в чистому CSS, але можна зробити за допомогою JavaScript. Це приклад jQuery :

<div class="snippet" data-lang="js" data-hide="false" data-console="false" data-babel="true"> <div class="snippet-code">

// use $.fn.one here to fire the event only once.
$(':required').one('blur keydown', function() {
  console.log('touched', this);
  $(this).addClass('touched');
});
/**
 * All required inputs initially are yellow.
 */
:required {
  background-color: lightyellow;
}

/**
 * If a required input has been touched and is valid, it should be white.
 */
.touched:required:valid {
  background-color: white;
}

/**
 * If a required input has been touched and is invalid, it should be pink.
 */
.touched:required:invalid {
  background-color: pink;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>






</div> </div>
20
додано
Це рішення, яке я віддаю перевагу, але вам більше не потрібна jQuery. Це можна зробити за допомогою простого Javascript.
додано Автор micah, джерело
Це просте рішення;)
додано Автор fegemo, джерело

Ці відповіді застаріли. Тепер ви можете зробити це, перевіривши псевдо-клас із заповнювачем за допомогою CSS.

<div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false"> <div class="snippet-code">

input:not(:placeholder-shown):invalid {
    background-color: salmon;
}
form:invalid button {
    background-color: salmon;
    pointer-events: none;
}
<form>
    <input type="email" placeholder="[email protected]" required>
    <button type="submit">Submit</button>
</form>
</div> </div>

Він починається з нормального тла і рожевий, коли ви вводите в нього неповну адресу електронної пошти.

14
додано
На жаль, це не працює, коли тільки необхідна перевірка. Він повинен показувати помилку, коли ви торкнулися необхідного поля або спробували надіслати форму з обов'язковими полями. Порожнє обов'язкове поле все одно покаже заповнювач.
додано Автор Björn Tantau, джерело
Я додав приклад перемикання кнопки подання на основі форми.
додано Автор Carl, джерело
Варто зазначити, що якщо ви дбаєте про підтримку IE або Edge, псевдо-клас : placeholder-показано взагалі не підтримується. Показати caniuse.com/#feat=css-
додано Автор Leo Napoleon, джерело

Існує подія html5 недійсне , яке відтворює елементи форми до того, як відбудеться подія submit для кожного елемента, який не проходить checkValidity. Ви можете використовувати цю подію, щоб застосувати клас, наприклад, до навколишньої форми і відобразити: неприпустимі стилі тільки після того, як ця подія відбудеться.

 $("form input, form select, form textarea").on("invalid", function() {
     $(this).closest('form').addClass('invalid');
 });

Після цього ваш CSS виглядатиме приблизно так:

:invalid { box-shadow: none; }
.invalid input:invalid,
.invalid textarea:invalid,
.invalid select:invalid { border: 1px solid #A90909 !important; background-color: #EEC2C2; }

Перший рядок видаляє стиль за замовчуванням, тому елементи форми виглядають нейтральними при завантаженні сторінки. Як тільки стає неприпустимим подія (коли користувач намагається подати форму), елементи помітно недійсними.

2
додано

Використовуючи перевірку форми HTML5, спробуйте скористатися веб-переглядачем для виявлення недійсних подань/полів, а не повторного винаходи колеса.

Слухайте для події недійсний , щоб додати до форми клас "недійсний". Якщо додано клас "недійсний", ви можете перейти до міста зі стилем форми, використовуючи селектори :

Наприклад:

// where myformid is the ID of your form
var myForm = document.forms.myformid;

var checkCustomValidity = function(field, msg) {
    if('setCustomValidity' in field) {
        field.setCustomValidity(msg);
    } else {
        field.validationMessage = msg;
    }
};

var validateForm = function() {

   //here, we're testing the field with an ID of 'name'
    checkCustomValidity(myForm.name, '');

    if(myForm.name.value.length < 4) {
        checkCustomValidity(
           //alerts fields error message response
            myForm.name, 'Please enter a valid Full Name, here.'
        );
    }
};

/* here, we are handling your question above, by adding an invalid
   class to the form if it returns invalid.  Below, you'll notice
   our attached listener for a form state of invalid */
var styleInvalidForm = function() {
    myForm.className = myForm.className += ' invalid';
}

myForm.addEventListener('input', validateForm, false);
myForm.addEventListener('keyup', validateForm, false);
myForm.addEventListener('invalid', styleInvalidForm, true);

Тепер просто сформуйте форму, як ви вважаєте за потрібне, на основі "недійсного" класу, який ми прикріпили.

Наприклад:

form.invalid input:invalid,
form.invalid textarea:invalid {
    background: rgba(255, 0, 0, .05);
    border-color: #ff6d6d;
    -webkit-box-shadow: 0 0 6px rgba(255, 0, 0, .35);
    box-shadow: 0 0 6px rgba(255, 0, 0, .35);
}
2
додано
Хіба це не переосмислює колесо, а не питання?
додано Автор Ry-, джерело

Mozilla піклується про це своїми : - moz-ui-недійсний псевдоклас, який застосовується лише до форм після взаємодії з ними. MDN не рекомендує використовувати це через відсутність підтримки. Однак ви можете змінити його для Firefox.

Спека для рівня 4 для спец. горизонт, який запропонує подібну поведінку.

Вибачте, якщо це не допоможе, але я сподіваюся, що він пропонує певний контекст.

1
додано

Ви можете зробити це так, щоб тільки елементи, які мають певний клас на них і , були потрібні, є рожевими. Додайте обробник подій до кожного необхідного елемента, який додає цей клас, коли ви залишаєте елемент.

Щось на зразок:

<script>
  document.addEventListener('DOMContentLoaded', function() {
    var required = document.querySelectorAll('input:required');
    for (var i = 0; i < required.length; ++i) {
      (function(elem) {
        function removeClass(name) {
          if (elem.classList) elem.classList.remove(name);
          else
            elem.className = elem.className.replace(
              RegExp('(^|\\s)\\s*' + name + '(?:\\s+|$)'),
              function (match, leading) {return leading;}
          );
        }

        function addClass(name) {
          removeClass(name);
          if (elem.classList) elem.classList.add(name);
          else elem.className += ' ' + name;
        }

       //If you require a class, and you use JS to add it, you end up
       //not showing pink at all if JS is disabled.
       //One workaround is to have the class on all your elements anyway,
       //and remove it when you set up proper validation.
       //The main problem with that is that without JS, you see what you're
       //already seeing, and stuff looks hideous.
       //Unfortunately, you kinda have to pick one or the other.


       //Let non-blank elements stay "touched", if they are already,
       //so other stuff can make the element :invalid if need be
        if (elem.value == '') addClass('touched');

        elem.addEventListener('blur', function() {
          addClass('touched');
        });

       //Oh, and when the form submits, they need to know about everything
        if (elem.form) {
          elem.form.addEventListener('submit', function() {
            addClass('touched');
          });
        };
      })(required[i]);
    }
  });
</script>

І, звичайно, він не буде працювати так само, як в IE8 або нижче, оскільки (a) DOMContentLoaded є відносно новим і не був стандартним, коли з'явився IE8, (b) IE8 використовує attachEvent замість стандарту DOM addEventListener і (c) IE8 не піклуватиметься про : required , оскільки він технічно не підтримує HTML 5.

1
додано

I created a small shim to deal with this in my codebase. I just start off with my <form/> element having the novalidate property along with a data-validate-on="blur" attribute. This watches for the first event of that type. This way you can still use the native :invalid CSS selectors for the form styling.

$(function() {
    $('[data-validate-on]').each(function() {
        var $form = $(this);
        var event_name = $form.data('validate-on');

        $form.one(event_name, ':input', function (event) {
            $form.removeAttr('novalidate');
        });
    });
});
1
додано

Хороший спосіб полягає в тому, щоб абстрагувати : invalid,: valid з класами CSS, а потім деяким JavaScript, щоб перевірити, чи було поле фокусування або не.

CSS:

input.dirty:invalid{ color: red; }
input.dirty:valid{ color: green; }

JS:

// Function to add class to target element
function makeDirty(e){
  e.target.classList.toggle('dirty');
}

// get form inputs
var inputs = document.forms[0].elements;

// bind events to all inputs
for(let input of inputs){
  input.addEventListener('invalid', makeDirty);
  input.addEventListener('blur', makeDirty);
  input.addEventListener('valid', makeDirty);
}

DEMO

0
додано