Delay HTML5 :invalid pseudo-class until the first event

前端 未结 13 2030
旧巷少年郎
旧巷少年郎 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 04:50

    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 */
    
    0 讨论(0)
  • 2020-11-30 04:53

    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>

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

    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');
            });
        });
    });
    
    0 讨论(0)
  • 2020-11-30 04:59

    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="me@example.com" 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.

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

    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);
    }
    
    0 讨论(0)
  • 2020-11-30 05:01

    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

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