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

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

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

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

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

由于我们只是想表示一个字段在焦点时是无效的,我们使用焦点伪类来触发无效的样式。 (当然,从一开始就将所有必填字段标记为无效将是一个糟糕的deviseselect。)

遵循这个逻辑,你的代码看起来像这样…

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

在这里创build一个小提琴: http : //jsfiddle.net/tbERP/

正如你所猜测的,正如你将从小提琴中看到的那样,这种技术只在元素具有焦点时才显示validation样式。 一旦将焦点移开,样式将被丢弃,无论其是否有效。 不以任何方式理想。

这在纯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> 

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

聆听invalid事件,向表单中添加一个“无效”类。 添加“无效”类后,您可以使用CSS3 :pseudoselect器为表单创build样式。

例如:

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

现在,只要根据我们所附的“无效”课程简单地devise您的表格。

例如:

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

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

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

第一行删除了默认样式,所以表单元素在页面加载时看起来是中性的。 一旦无效事件触发(当用户尝试提交表单),元素将被视为无效。

你可以这样做,只有那些具有特定类别的元素才是粉红色的。 添加一个事件处理程序到每个需要的元素,当你离开元素时添加这个类。

就像是:

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

我在代码库中创build了一个小垫片来处理这个问题。 我刚刚开始使用具有novalidate属性的<form/>元素以及data-validate-on="blur"属性。 这就注意到这种types的第一个事件。 这样,你仍然可以使用native :invalid cssselect器进行表单样式设置。

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

一个好方法是抽象:invalid, :valid用CSS类:invalid, :valid ,然后用一些JavaScript来检查input字段是否被聚焦。

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