Подтвердить что ты не робот

Задержка HTML5: недопустимый псевдокласс до первого события

Недавно я обнаружил, что псевдокласс класса :invalid применяется к элементам формы required, как только загружается страница. Например, если у вас есть этот код:

<style>
input:invalid { background-color: pink; color: white; }
input:valid { background-color: white; color: black; }
</style>
…
<input name="foo" required />

Затем ваша страница будет загружена с пустым розовым элементом ввода. Валидация, встроенная в HTML5, отличная, но я не думаю, что большинство пользователей ожидают, что форма будет проверена, прежде чем у них будет возможность ввести какие-либо значения вообще. Есть ли способ отложить применение псевдокласса до первого события, влияющего на этот элемент (форма отправки, размытия, изменения, независимо от того, что подходит)? Можно ли сделать это без JavaScript?

4b9b3361

Ответ 1

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

Поскольку мы хотим только отметить, что поле недействительно, когда оно имеет фокус, мы используем псевдокласс для фокуса, чтобы вызвать недействительный стиль. (Естественно, пометить все обязательные поля как недопустимые с самого начала будет плохой выбор дизайна.)

Следуя этой логике, ваш код будет выглядеть примерно так:

<style>
    input:focus:required:invalid {background-color: pink; color: white;}
    input:required:valid {background-color: white; color: black; }
<style>

Создал скрипку здесь: http://jsfiddle.net/tbERP/

Как вы могли догадаться, и, как вы увидите из скрипки, этот метод показывает только стиль проверки, когда элемент имеет фокус. Как только вы перемещаете фокус, стилизация отбрасывается независимо от того, действительна она или нет. Не идеален никакими средствами.

Ответ 2

Это невозможно в чистом CSS, но можно сделать с помощью JavaScript. Это пример jQuery:

// 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>
<p>
  <label>
    Name:
    <input type="text" required> *required
  </label>
</p>
<p>
  <label>Age:
    <input type="text">
  </label>
</p>

Ответ 3

Эти ответы устарели. Теперь вы можете сделать это, проверив псевдокласс с помощью CSS.

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>

Ответ 4

Я создал небольшую прокладку, чтобы справиться с этим в моей кодовой базе. Я просто начинаю с моего элемента <form/>, имеющего свойство novalidate вместе с атрибутом data-validate-on="blur". Это наблюдает за первым событием такого типа. Таким образом, вы можете использовать собственные селектора :invalid css для стилизации формы.

$(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');
        });
    });
});

Ответ 5

Mozilla заботится об этом с помощью своего собственного псевдокласса : -moz-ui-invalid, который применяется только к формам после их взаимодействия. MDN не рекомендует использовать это из-за отсутствия поддержки. Тем не менее, вы можете изменить его для Firefox.

На горизонте есть спецификация уровня 4 для : недопустимой пользователем спецификации, которая будет предлагать аналогичное поведение.

Извините, если это не поможет, но я надеюсь, что это даст некоторый контекст.

Ответ 6

При использовании проверки формы HTML5 попробуйте использовать браузер для обнаружения недопустимых представлений/полей, вместо того, чтобы повторно изобретать колесо.

Прослушайте событие invalid, чтобы добавить в форму форму "недействительно". С добавленным классом "недействительный" вы можете отправиться в город, создав форму с помощью селекторов CSS3 :pseudo.

Например:

// 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);
}

Ответ 7

Существует событие html5 invalid, которое запускает элементы формы перед событием 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; }

Первая строка удаляет стиль по умолчанию, поэтому элементы формы выглядят нейтральными при загрузке страницы. Как только недействительное событие срабатывает (когда пользователь пытается отправить форму), элементы явно отображаются недействительными.

Ответ 8

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

Что-то вроде:

<style>
  input.touched:invalid { background-color: pink; color: white; }
  input.touched:valid { background-color: white; color: black; }
</style>
<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-standard addEventListener и (c) IE8 не будет заботиться о :required в любом случае, так как он технически не поддерживает HTML 5.

Ответ 9

Хорошим способом является абстрагирование :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

Ответ 10

Это версия kzh ответа VanillaJS (без jQuery)

{
  let f = function() {
    this.classList.add('touched')
  }
  document
    .querySelectorAll('input')
    .forEach((e) => {
      e.addEventListener('blur', f, false)
      e.addEventListener('keydown', f, false)
    })
}
/**
 * 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;
}
<p><label>
  Name:
  <input type="text" required> *required
</label></p>
<p><label>Age:
  <input type="text">
</label></p>

Ответ 11

Вот мой метод, позволяющий избежать стилизации по умолчанию любого несфокусированного ввода как недопустимого, вам просто нужно добавить простую команду js onFocus чтобы позволить веб-странице идентифицировать focused и unfocused входы, чтобы все входные данные не отображались в стиле недопустимых при первое место.

<style>
input.focused:required:invalid { background-color: pink; color: white; }
input:valid { background-color: white; color: black; }
</style>
…
<input name="foo" class="notfocused" onFocus="document.activeElement.className='focused';" required />

Попробуйте сами ниже:

input.focused:required:invalid {
  background-color: pink;
  color: white;
}

input:required:valid {
  background-color: darkseagreen;
  color: black;
}
<label>At least 1 charater:</label><br />
<input type="text" name="foo" class="notfocused" onFocus="document.activeElement.className='focused';" required />

Ответ 12

Я не могу комментировать, но использовать @Carl очень полезный ответ относительно использования: not (: placeholder-показ). Как уже упоминалось в другом комментарии, он по-прежнему будет отображать недопустимое состояние, если у вас НЕТ заполнителя (как требуют некоторые дизайны форм).

Чтобы решить эту проблему, просто добавьте пустой заполнитель, например, так

<input type="text" name="username" placeholder=" " required>

Тогда ваш CSS, что-то вроде

:not(:placeholder-shown):invalid{ background-color: #ff000038; }

Работал на меня!

Ответ 13

Исходя из идеи Agouseh, вы можете иметь немного javascript, чтобы сказать, когда была нажата кнопка отправки, и чтобы в это время отображалась проверка.

Javascript добавит класс (например, submit-focussed) в поле формы, когда кнопка submit будет сфокусирована или нажата, что затем позволит CSS стилизовать недопустимые входные данные.

Это следует из лучшей практики показа обратной связи проверки после того, как пользователь завершил заполнение полей, поскольку согласно исследованию нет никакой дополнительной выгоды, чтобы показать это во время процесса.

document
  .querySelector('input[type=submit]')
  .onfocus = function() {
    this
      .closest('form')
      .classList
      .add('submit-focussed');
  };
form.submit-focussed input:invalid {
  border: thin solid red;
}
<form>
  <label>Email <input type="email" required="" /></label>
  <input type="submit" />
</form>