Why is input:invalid true when the input is empty?

2019-09-11 23:33发布

问题:

Currently I'm trying to emulate this example. This works fine, however it has got one big restraint: it only works when your input type is text.

When you use another input type, let's say email, a basic string isn't valid, so the placeholder falls over the text.

So in my eyes there are to solutions to this problem:

  1. Use type=text everywhere, which is kinda crappy, because on mobile phones for example you won't get the email-type keyboard.
  2. Use JavaScript to check if the input has a value.

I hope I'm missing something and there's another example to achieve want I want. In a perfect world, an empty input wouldn't be validated, so the placeholder will show its normal state. Then when the user fills in any kind of data, the validation will begin. Is this possible with pure CSS?

Thanks all!

HTML:

<fieldset id="fieldset1">
    <input type="text" required />
    <label>First name</label>
</fieldset>
<fieldset id="fieldset2">
    <input type="email" required />
    <label>Email address</label>
</fieldset>

CSS:

fieldset {
    position: relative;
    margin:40px 0 0 0;
    padding:0;
    border:none;
}
fieldset input {
    height: 2.5rem;
    line-height: 2.25rem;
    padding: 0 0.9375rem;
    color: white;
    font-size: 0.75rem;
    font-weight: 700;
    border: none;
    outline: none !important;
    -webkit-box-shadow: none !important;
    box-shadow: none !important;
    background: #9a9a9a;
    display: block;
    width: 100%;
    border: 2px solid transparent;
    -webkit-transition: all 100ms ease-out;
    transition: all 100ms ease-out;
    border-radius: 0px !important;
    -webkit-border-radius: 0px !important;
}
fieldset label {
    position: absolute;
    color: white;
    font-size: 0.75rem;
    text-transform: uppercase;
    font-weight: bold;
    -webkit-transition: all 100ms ease-out;
    transition: all 100ms ease-out;
    line-height: 2.5rem;
    left: 0.9375rem;
    top: 0;
    display: block;
    text-align: left;
}
fieldset input:focus + label, 
fieldset input:valid + label {
    top: -1.875rem;
    color: black; 
}

I made a JSFiddle to illustrate my problem, view it here

EDIT: since it's not clear to 1l13v what I want to achieve, I'll repeat myself: I know a string isn't a valid email address, so the solution I've now will never work with any other input type than text.

I want to achieve this:

  1. Have a CSS-only solution to check if a input has any value whatsoever. If its empty, I can show the placeholder at its normal position, when it isn't, I can show the placeholder above the input.
  2. Make a input[type="email"]:invalid make return false when the input is completely empty.

If both these solutions aren't possible, I think my only solution is to switch to Javascript to solve my problem, unless there's a solution which I'm forgetting. I hope I'm forgetting something, I wan't to avoid using Javascript for this problem.

I used this as my solution:

function checkInputValue() {
    if($(this).val() !== ''){
        $(this).parents('fieldset').addClass('valid');
    } else {
        $(this).parents('fieldset').removeClass('valid');
    }
};

$('.input1').on('blur', checkInputValue); // Check if input has a value

回答1:

Your problem is that you enter normal text and you want the email label EMMAIL ADDRESS to go up, but this isn't happening when you loose focus of that input email because after you leave the input text is not valid, i.e. your text is not like: email@something.com

This will never be applied unless your input is a valid email:

fieldset input:valid + label {
    top: -1.875rem;
    color: black; 
}

About input email:

Depending on browser support, the e-mail address can be automatically validated when submitted.

Some smartphones recognize the email type, and adds ".com" to the keyboard to match email input.

UPDATE

If you still wanna have your label above email despite its value is not a valid email, then you must use javascript.

Try this code using jQuery:

var emailInput = $('#fieldset2 > input');
var label = $('#fieldset2 > label');

    emailInput.blur( function(){
    if(emailInput.val() !== ''){
        label.addClass('valid');
    } else {
        label.removeClass('valid');
    }
});

and this css class:

.valid {
    top: -1.875rem;
    color: black; 
}

i.e. same rules as your fieldset label

See this fiddle