【问题标题】:CSS autofill and validationCSS 自动填充和验证
【发布时间】:2020-06-12 20:16:57
【问题描述】:

我正在处理一些用户输入的样式,但遇到了一个绊脚石。

我不反对用户使用自动完成功能(我个人讨厌在某些网站上关闭它),因为我认为它真的很方便。我知道如何使用-webkit-autofill 设置它的样式。但是,自动完成将始终导致字段获得:valid 状态,即使它们不应该这样做。

例如,我将一个字段设置为至少 5 个字符长:

<input type="text" required class=namefileds id=first_name name=Name[] placeholder="Enter your first name" minlength="5">

我已经为有效/无效的情况设置了 CSS 样式:

#checkout_form input:invalid {
    padding-right: calc(1.5em + .75rem);
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: center right calc(.375em + .1875rem);
    background-size: calc(.75em + .375rem) calc(.75em + .375rem);
}

    #checkout_form input:valid {
    padding-right: calc(1.5em + 0.75rem);
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23ffcc00' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: right calc(0.375em + 0.1875rem) center;
    background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}

这很好用。为了使自动填充样式很好地工作(在所有 webkit 浏览器上),我添加了以下 CSS 规则:

@-webkit-keyframes autofillvalid {
     0%,100% {
         color: #ffcc00;
         background:none;
         padding-right: calc(1.5em + 0.75rem);
         background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23ffcc00' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
         background-repeat: no-repeat;
         background-position: right calc(0.375em + 0.1875rem) center;
         background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
    }
}

 @-webkit-keyframes autofillinvalid {
    0%,100% {
        background:none;
        padding-right: calc(1.5em + .75rem);
        background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
        background-repeat: no-repeat;
        background-position: center right calc(.375em + .1875rem);
        background-size: calc(.75em + .375rem) calc(.75em + .375rem);
    }
}

input:-webkit-autofill:valid {
     -webkit-animation-delay: 1s; /* Safari support - any positive time runs instantly */
     -webkit-animation-name: autofillvalid;
     -webkit-animation-fill-mode: both;
 }

 input:-webkit-autofill:invalid {
     -webkit-animation-delay: 1s; /* Safari support - any positive time runs instantly */
     -webkit-animation-name: autofillinvalid;
     -webkit-animation-fill-mode: both;
 }

我的问题是,如果自动填充的名称只有四个字符长,它应该得到:invalid 状态,但自动填充总是生成:valid 状态。其他状态选择器看起来工作正常,例如::focus

我看过this 的问题,但我现在不想触发额外的java 脚本,这一切都与视觉有关,验证将在用户与其他事物交互之后进行。这就是问题所在,如果自动填充给人一种错误的感觉,即数据有效,那么在稍后阶段显示为无效真的很令人沮丧......

知道如何仅通过 CSS 设置样式吗?

如果我必须使用 JS: 另一个问题是在没有手动更改值之前,样式不会在字段上更新,在字段上触发 jQuery .change() 事件没有帮助

在写这个问题时,我决定做更多的挖掘工作,更糟糕的是,自动填充使元素 document.getElementById("first_name").checkValidity() 返回真,而它不应该返回真。

因此,虽然我从一个 CSS 问题开始,但现在我更倾向于问这种行为是否会被视为错误?

编辑 1: 由于checkValidity() 返回true,我尝试提交表单(通常不应该提交,因为不满足验证条件)并且提交时没有任何问题。当然,黄金法则永远不信任用户数据,服务器端会拒绝它,但我认为这不应该发生,简单的自动填充不应该自动意味着数据是有效的。

【问题讨论】:

    标签: javascript html css google-chrome webkit


    【解决方案1】:

    希望对你有所帮助:

    使用“pattern”属性而不是“minlength”。

    #checkout_form input:invalid{
        padding-right: calc(1.5em + .75rem);
        background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
        background-repeat: no-repeat;
        background-position: center right calc(.375em + .1875rem);
        background-size: calc(.75em + .375rem) calc(.75em + .375rem);
        }
        #checkout_form input:valid{
        padding-right: calc(1.5em + 0.75rem);
        background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23ffcc00' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
        background-repeat: no-repeat;
        background-position: right calc(0.375em + 0.1875rem) center;
        background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
        }
        
        @-webkit-keyframes autofillvalid {
        0%,100% {
            color: #ffcc00;
            background:none;
             padding-right: calc(1.5em + 0.75rem);
            background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23ffcc00' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
            background-repeat: no-repeat;
            background-position: right calc(0.375em + 0.1875rem) center;
            background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
        }
    }
        @-webkit-keyframes autofillinvalid {
        0%,100% {
            background:none;
            padding-right: calc(1.5em + .75rem);
            background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
            background-repeat: no-repeat;
            background-position: center right calc(.375em + .1875rem);
            background-size: calc(.75em + .375rem) calc(.75em + .375rem);
        }
    }
    
        input:-webkit-autofill:valid {
            -webkit-animation-delay: 1s; /* Safari support - any positive time runs instantly */
            -webkit-animation-name: autofillvalid;
            -webkit-animation-fill-mode: both;
        }
        input:-webkit-autofill:invalid {
            -webkit-animation-delay: 1s; /* Safari support - any positive time runs instantly */
            -webkit-animation-name: autofillinvalid;
            -webkit-animation-fill-mode: both;
        }
    <form id="checkout_form" >
      <input type="text" required class=namefileds id=first_name name=Name[] placeholder="Enter your first name" pattern=".{5,}">
      <button type="submit">submit</button>
    </form>

    【讨论】:

    • 谢谢。你的答案是正确的,但是另一个答案更完整,并继续解释为什么使用模式而不是 minLenght 并指出验证实际上出了什么问题,因此赏金授予@Richard跨度>
    【解决方案2】:

    这是一个非常有趣的问题。不过,我对某事感到好奇。 Chrome 只会在提交表单时保存autocomplete 值(如here 所述)。从逻辑上讲,如果输入的 minlength 为 5,而您输入的内容长度为 4,则您将无法首先提交表单。因此,不应保存无效的自动完成值。你是怎么第一次遇到这种情况的?我只能通过设置minlength,提交,然后设置minlength 并尝试自动填充来重现它。

    要回答您的问题,此行为不是错误。 minlength 不工作,因为它的设计不能验证autofill 插入的值。阅读下文。

    为什么minlength 不起作用?

    当值的长度小于指定的minlength 时,为什么minlength 不会使autocomplete 给出的值无效? HTML Standard by WHATWG中提到,minlength有这个约束验证:

    如果一个元素有一个最小允许值长度,它的脏值标志为真,它的值最后被用户编辑更改(与脚本所做的更改相反),它的值不是空字符串,并且元素的 API 值的 JavaScript 字符串长度小于元素的最小允许值长度,则元素过短。

    很明显,只有minlength 的值被用户编辑而不是脚本更改时,该值才会被验证。进一步阅读,我们可以推断出autofill 的值是由脚本插入的(阅读here)。我们可以通过执行以下操作来测试minlength 在输入值被脚本更改时不验证输入值(请在输入中插入单词“Testing”):

    const input = document.querySelector('input')
    input.addEventListener('keyup', e => {
      if (input.value === "Testing") input.value = "Test"
    })
    input:invalid {
      outline: 1px solid red;
    }
    &lt;input type="text" minlength="5"&gt;

    您可以看到,当input 的值被脚本更改为“Test”时,它不会费心去验证它。

    使用pattern

    另一方面,pattern 没有约束验证,即必须通过用户编辑来更改值。你可以阅读它的constraint validation here。因此,您仍然可以使用脚本更改input 的值,它仍然可以工作。再次尝试在input 中输入“Testing”:

    const input = document.querySelector('input')
    input.addEventListener('keyup', e => {
      if (input.value === "Testing") input.value = "Test"
    })
    input:invalid {
      outline: 1px solid red;
    }
    &lt;input type="text" pattern="[0-9a-zA-Z]{5,}"&gt;

    当它更改为“测试”时,它会被pattern 无效并导致 CSS 触发。这意味着您可以使用pattern 来验证autofill 给出的值。 (仍然很好奇这个错误的autofill 值是如何保存在首位的。)

    这是一个使用pattern 来验证autofill 给出的input 并进行一些调整的解决方案:

    * {
      box-sizing: border-box;
      margin: 0;
      font-family: Helvetica;
    }
    
    body {
      padding: 20px;
    }
    
    #checkout_form * {
      display: block;
      margin: 1em;
    }
    
    #first_name {
      padding: 10px;
      border-radius: 5px;
      width: 400px;
      border: 1px solid #00000044;
      outline: none;
    }
    
    #first_name::placeholder {
      color: #00000040;
    }
    
    #submit_form {
      padding: 10px;
      border-radius: 5px;
      border: none;
      background: #7F00FF;
      color: #ffffffee;
      width: 200px;
    }
    
    #checkout_form input:invalid {
      padding-right: calc(1.5em + .75rem);
      background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
      background-repeat: no-repeat;
      background-position: center right calc(.375em + .1875rem);
      background-size: calc(.75em + .375rem) calc(.75em + .375rem);
      
      border: 1px solid #CC0000ee;
    }
    
    #checkout_form input:valid {
      padding-right: calc(1.5em + 0.75rem);
      background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23ffcc00' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
      background-repeat: no-repeat;
      background-position: right calc(0.375em + 0.1875rem) center;
      background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
      
      border: 1px solid #00cc00ee;
    }
    
    @-webkit-keyframes autofillvalid {
      0%,
      100% {
        color: #ffcc00;
        background: none;
        padding-right: calc(1.5em + 0.75rem);
        background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23ffcc00' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
        background-repeat: no-repeat;
        background-position: right calc(0.375em + 0.1875rem) center;
        background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
      }
    }
    
    @-webkit-keyframes autofillinvalid {
      0%,
      100% {
        background: none;
        padding-right: calc(1.5em + .75rem);
        background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
        background-repeat: no-repeat;
        background-position: center right calc(.375em + .1875rem);
        background-size: calc(.75em + .375rem) calc(.75em + .375rem);
      }
    }
    
    input:-webkit-autofill:valid {
      -webkit-animation-name: autofillvalid;
      -webkit-animation-fill-mode: both;
    }
    
    input:-webkit-autofill:invalid {
      -webkit-animation-name: autofillinvalid;
      -webkit-animation-fill-mode: both;
    }
    <form id="checkout_form">
      <input type="text" required id="first_name" name="fname" placeholder="Enter your first name" pattern="[0-9a-zA-Z]{5,}" autocomplete="given-name" title="First Name should be at least 5 characters and must consist only of alphabets and/or numbers">
      <button id="submit_form" type="submit">Submit</button>
    </form>

    此外,我强烈建议阅读更多关于 autofill 以及如何更好地利用它的内容 here

    【讨论】:

    • 你的回答很有道理,我会在几天后检查一下,因为我在路上。我把那个 minlength 值放在那里只是为了检查我的样式是否适用于有效/无效字段(不是我真的需要它)但看起来我已经设法选择了一个非常错误的约束来进行测试......跨度>
    • @EmilBorconi 太棒了!稍后告诉我答案对你有什么影响。
    猜你喜欢
    • 2023-03-16
    • 2016-01-15
    • 2013-12-01
    • 2011-06-28
    • 2011-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多