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

时间:2011-10-27 18:43:29

标签: html5 validation usability

我最近发现,: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 个答案:

答案 0 :(得分:36)

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 :(得分: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>

答案 2 :(得分:17)

这些答案已过时。现在,您可以通过使用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 :(得分: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');
        });
    });
});

答案 4 :(得分:3)

Mozilla使用自己的:-moz-ui-invalid伪类来处理此问题,该伪类仅在与表单进行交互之后才适用。由于缺乏支持,MDN不建议使用此功能。但是,您可以为Firefox对其进行修改。

即将到来的:user-invalid规范有4级规范,将提供类似的行为。

很抱歉,如果这样做没有帮助,但我希望它提供了一些上下文。

答案 5 :(得分:2)

在使用HTML5表单验证时,尝试使用浏览器检测无效的提交/字段,而不是重新发明轮子。

收听invalid事件,向表单添加“无效”类。添加“无效”课程后,您可以使用CSS3 :pseudo选择器为您的表单设置样式。“/ p>

例如:

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

答案 6 :(得分: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; }

第一行删除默认样式,因此表单元素在页面加载时看起来是中性的。一旦无效事件触发(当用户尝试提交表单时),元素就会明显无效。

答案 7 :(得分: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使用{{1}而不是DOM标准attachEvent和(c)IE8无论如何都不会关心addEventListener,因为它在技术上不支持HTML 5。

答案 8 :(得分: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

答案 9 :(得分:1)

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

答案 10 :(得分: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 />

答案 11 :(得分:0)

我无可奉告,但是@Carl对于使用:not(:placeholder-shown)非常有用。如要提及的另一条评论,如果您没有占位符(某些表单设计要求),它将仍然显示无效状态。

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

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

然后是CSS,类似

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

为我工作!

答案 12 :(得分: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 */