Delay HTML5 :invalid pseudo-class until the first event

前端 未结 13 2066
旧巷少年郎
旧巷少年郎 2020-11-30 04:35

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 cod

相关标签:
13条回答
  • 2020-11-30 05:02

    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>

    0 讨论(0)
  • 2020-11-30 05:04

    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!

    0 讨论(0)
  • 2020-11-30 05:05

    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.

    0 讨论(0)
  • 2020-11-30 05:06

    Mozilla takes care of this with their own :-moz-ui-invalid pseudoclass that only applies to forms after they've been interacted with. MDN does not recommend using this due to 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.

    Sorry if this doesn't help, but I hope it offers some context.

    0 讨论(0)
  • 2020-11-30 05:06

    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.

    0 讨论(0)
  • 2020-11-30 05:07

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

    0 讨论(0)
提交回复
热议问题