延迟 HTML5:无效伪类直到第一个事件发生

发布于 2024-12-12 06:55:05 字数 441 浏览 0 评论 0原文

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

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

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

I recently discovered that the :invalid pseudo-class applies to required form elements as soon as the page loads. For example, if you have this code:

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

Then your page will load with an empty pink input element on it. Having validation built in to HTML5 is great, but I don't think most users expect the form to validate before they've had a chance to enter any values at all. Is there any way to delay the application of the pseudo-class until the first event affecting that element (form submit, blur, change, whatever's appropriate)? Is it possible to do this without JavaScript?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

晚风撩人 2024-12-19 06:55:05

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

因为我们只想表示一个字段一旦出现就无效
focus,我们使用 focus 伪类来触发无效的样式。
(当然,从一开始就将所有必填字段标记为无效
将是一个糟糕的设计选择。)

按照这个逻辑,您的代码将看起来像这样...

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

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

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

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

Since we only want to denote that a field is invalid once it has
focus, we use the focus pseudo-class to trigger the invalid styling.
(Naturally, flagging all required fields as invalid from the start
would be a poor design choice.)

Following this logic, your code would look something like this...

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

Created a fiddle here: http://jsfiddle.net/tbERP/

As you'd guess, and as you'll see from the fiddle, this technique only shows the validation styling when the element has focus. As soon as you move focus off, the styling is dropped, regardless of whether it is valid or not. Not ideal by any means.

为你鎻心 2024-12-19 06:55:05

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

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

These answers are out of date. Now you can do this by checking for a placeholder pseudo-class with 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>

It starts with a normal background and turns pink as you enter you incomplete email address into it.

音盲 2024-12-19 06:55:05

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

This is not possible in pure CSS, but can be done with JavaScript. This is a 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>

挽你眉间 2024-12-19 06:55:05

这是 kzh答案

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

This is a VanillaJS (no jQuery) version of kzh's answer

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

眼眸印温柔 2024-12-19 06:55:05

Mozilla 用自己的 :-moz-ui-invalid 伪类,仅适用于与表单交互后的表单。由于缺乏支持,MDN 不建议使用此方法。但是,您可以针对 Firefox 进行修改。

:user-invalid< 有一个 4 级规范/a> 即将推出的规范将提供类似的行为。

Mozilla takes care of this with its own :-moz-ui-invalid pseudoclass that only applies to forms after they've been interacted with. MDN does not recommend using this due to a lack of support. However, you can modify it for Firefox.

There's a level 4 spec for a :user-invalid spec on the horizon that will offer similar behavior.

宁愿没拥抱 2024-12-19 06:55:05

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

I created a small shim to deal with this in my codebase. I just start off with my <form/> element having the novalidate property along with a data-validate-on="blur" attribute. This watches for the first event of that type. This way you can still use the native :invalid css selectors for the form styling.

$(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');
        });
    });
});
℡Ms空城旧梦 2024-12-19 06:55:05

对于未通过 checkValidity 的每个元素,在发生 submit 事件之前,会在表单元素上触发一个 html5 invalid 事件。您可以使用此事件将类应用于周围的表单,并仅在此事件发生后显示 :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; }

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

There is a html5 invalid event that fires on form elements before the submit event occurs for each element that does not pass checkValidity. You can use this event to apply a class for example to the surrounding form and display :invalid styles only after this event occurs.

 $("form input, form select, form textarea").on("invalid", function() {
     $(this).closest('form').addClass('invalid');
 });

Your CSS would then look something like this:

:invalid { box-shadow: none; }
.invalid input:invalid,
.invalid textarea:invalid,
.invalid select:invalid { border: 1px solid #A90909 !important; background-color: #EEC2C2; }

The first line removes the default styling, so form elements look neutral at page load. As soon as the invalid event fires (when a user tries to submit the form), the elements are visibly rendered invalid.

凉薄对峙 2024-12-19 06:55:05

您可以将其设置为只有具有特定类的元素才是必需的,是粉红色的。向每个必需的元素添加一个事件处理程序,以便在您离开该元素时添加该类。

当然

<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 使用 < code>attachEvent 而不是 DOM 标准的 addEventListener,并且 (c) IE8 无论如何都不会关心 :required,因为它不会技术支持HTML 5。

You could make it so that only elements that have a certain class on them and are required, are pink. Add an event handler to each required element that adds that class when you leave the element.

Something like:

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

And of course, it won't work as is in IE8 or below, as (a) DOMContentLoaded is relatively new and wasn't standard when IE8 came out, (b) IE8 uses attachEvent rather than the DOM-standard addEventListener, and (c) IE8 isn't going to care about :required anyway, as it doesn't technically support HTML 5.

笑咖 2024-12-19 06:55:05

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

While using HTML5 form validation, try to use the browser to detect for invalid submissions/fields, rather than re-inventing the wheel.

Listen for the invalid event to add a class of 'invalid' to your form. With the 'invalid' class added, you can go to town with styling your form using CSS3 :pseudo selectors.

For example:

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

Now, simply style your form as you see fit based on the 'invalid' class we've attached.

For example:

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);
}
在风中等你 2024-12-19 06:55:05

一个好方法是使用 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);
}

演示

A good way is to abstract :invalid, :valid with a CSS classes and then some JavaScript to check if the input field was focused or not.

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

拥有 2024-12-19 06:55:05

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

Following on from agouseh's idea, you can have a bit of javascript to tell when the submit button has been focussed, and have validation show up at that time.

The javascript will add a class (eg. submit-focussed) to the form field when the submit button is focussed or clicked, which then allows the CSS to style invalid inputs.

This follows the best practice of showing validation feedback after the user has finished filling in the fields, as according to research there is no additional benefit to showing it during the process.

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 alternative

(function($) {
  $('input[type=submit]').on('focus', function() {
    $(this)
      .parent('form')
      .addClass('submit-focussed');
  });
})(jQuery); /* WordPress compatible */
转身以后 2024-12-19 06:55:05

从 CSS 选择器级别 4 开始,您现在可以使用 :user-invalid 选择器,从而大大简化了这一过程。

:user-invalid 和 :user-valid 伪类分别表示输入不正确或正确的元素,但仅在用户与其进行大量交互之后。

https://www.w3.org/TR/selectors-4/#用户伪

input:user-invalid {
  background-color: pink;
  color: white;
}
<form>
  <input name="foo" required />
  <button type="submit">Submit</button>
</form>

Since CSS Selectors Level 4 you can now use the :user-invalid selector simplifying this greatly.

The :user-invalid and the :user-valid pseudo-classes represent an element with incorrect or correct input, respectively, but only after the user has significantly interacted with it.

https://www.w3.org/TR/selectors-4/#user-pseudos

input:user-invalid {
  background-color: pink;
  color: white;
}
<form>
  <input name="foo" required />
  <button type="submit">Submit</button>
</form>

開玄 2024-12-19 06:55:05

这是我的方法,以避免任何未聚焦的输入的默认样式无效,您只需添加一个简单的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 />

Here is my method to avoid the default styling of any unfocused input as invalid, you just have to add a simple js command onFocus to let the webpage to identify focused and unfocused inputs, so all the input will not appear in the style of invalid at first place.

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

Try it yourself below:

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

薄凉少年不暖心 2024-12-19 06:55:05

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

要解决这个问题,只需添加一个空占位符,如下所示

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

然后你的 CSS,如

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

Worked for me!

I can't comment, but to go with @Carl's very useful answer regarding using :not(:placeholder-shown). As another comment mentioned, this will still show the invalid state if you have NO placeholder (as some form designs call for).

To solve this, simply add an empty placeholder like so

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

Then your CSS, something like

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

Worked for me!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文