延迟HTML5:第一个事件之前的伪类无效

问题描述 投票:56回答:13

我最近发现:invalid伪类在页面加载时立即应用于required表单元素。例如,如果您有此代码:

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

然后你的页面将加载一个空的粉红色输入元素。对HTML5内置验证非常好,但我认为大多数用户都不希望表单在有机会输入任何值之前进行验证。有没有办法延迟伪类的应用,直到影响该元素的第一个事件(表单提交,模糊,更改,任何适当的)?没有JavaScript可以做到这一点吗?

html5 validation usability
13个回答
35
投票

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/

正如您所猜测的那样,正如您从小提琴中看到的那样,此技术仅在元素具有焦点时显示验证样式。只要关闭焦点,样式就会被删除,无论它是否有效。无论如何都不理想。


1
投票

一个好方法是用CSS类抽象:invalid, :valid然后用一些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
投票

这是我的方法,以避免任何未聚焦输入的默认样式为无效,你只需要添加一个简单的js命令onFocus让网页识别focusedunfocused输入,所以所有的输入将不会出现在无效的样式中第一名。

<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 />

0
投票

我不能发表评论,但要跟@ Carl关于使用的非常有用的答案:not(:占位符 - 显示)。正如另一条评论提到的,如果您没有占位符(如某些表单设计所要求的那样),这仍将显示无效状态。

要解决此问题,只需添加一个空占位符即可

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

然后你的CSS,像

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

为我工作!


0
投票

agousehidea之后,您可以通过一些javascript告诉我们何时关注提交按钮,并在此时显示验证。

当聚焦或单击提交按钮时,javascript将向表单字段添加一个类(例如,submit-focussed),然后允许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>

jQuery替代品

(function($) {
  $('input[type=submit]').on('focus', function() {
    $(this)
      .parent('form')
      .addClass('submit-focussed');
  });
})(jQuery); /* WordPress compatible */

20
投票

这在纯CSS中是不可能的,但可以使用JavaScript完成。这是一个jQuery example

// 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
投票

这些答案已过时。现在,您可以通过使用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>

它以正常背景开始,并在您输入不完整的电子邮件地址时变为粉红色。


3
投票

我在我的代码库中创建了一个小垫片来处理这个问题。我刚开始使用具有<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');
        });
    });
});

3
投票

Mozilla使用他们自己的:-moz-ui-invalid伪类来处理这个问题,这些伪类只有在与形式交互后才适用于表格。由于缺乏支持,MDN不建议使用此功能。但是,您可以为Firefox修改它。

对于地平线上的:user-invalid规范,有一个4级规范将提供类似的行为。

对不起,如果这没有帮助,但我希望它提供一些上下文。


2
投票

在使用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);
}

2
投票

在没有通过checkValidity的每个元素发生invalid事件之前,有一个html5 submit事件触发表单元素。您可以使用此事件将类应用于周围的表单并显示:仅在此事件发生后才会显示无效样式。

 $("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
投票

这是kzhanswer的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>

1
投票

你可以这样做,只有那些在它们上面有特定类并且是必需的元素才是粉红色的。向每个必需元素添加一个事件处理程序,在离开元素时添加该类。

就像是:

<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。

© www.soinside.com 2019 - 2024. All rights reserved.