Задержка HTML5: неверный псевдокласс до первого события - PullRequest
57 голосов
/ 27 октября 2011

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

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

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

Ответы [ 13 ]

35 голосов
/ 27 октября 2011

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

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

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

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

Здесь создана скрипка: http://jsfiddle.net/tbERP/

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

20 голосов
/ 28 июня 2013

Это невозможно в чистом 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>
17 голосов
/ 08 января 2018

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

input:not(:placeholder-shown):invalid {
    background-color: salmon;
}
form:invalid button {
    background-color: salmon;
    pointer-events: none;
}
<form>
    <input type="email" placeholder="me@example.com" required>
    <button type="submit">Submit</button>
</form>

Он начинается с обычного фона и становится розовым, когда вы вводите в него неполный адрес электронной почты.

3 голосов
/ 30 июня 2018

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

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

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

3 голосов
/ 17 марта 2016

Я создал небольшую шимму, чтобы справиться с этим в моей кодовой базе.Я только начинаю с моего элемента <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');
        });
    });
});
2 голосов
/ 06 марта 2019

Это версия 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>
2 голосов
/ 30 августа 2015

Существует событие 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; }

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

2 голосов
/ 26 октября 2013

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

Прослушайте событие invalid, чтобы добавить класс 'invalid'к вашей форме.С добавленным классом '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);
}
1 голос
/ 28 сентября 2017

Хороший способ - абстрагироваться :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

1 голос
/ 04 апреля 2013

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

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

<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 addEventListener, и (c) IE8 не собираетсяв любом случае, заботьтесь о :required, поскольку он технически не поддерживает HTML 5.

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