javascript - CSS自动填充和验证

标签 javascript html css google-chrome webkit

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

我没有反对用户使用自动完成功能(我个人讨厌在某些站点上将其关闭),因为我认为这非常方便。我知道如何用-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()元素在不应该返回时返回true。

因此,当我从一个CSS问题开始时,现在我更倾向于问这是否可以视为错误?

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

最佳答案

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

要回答您的问题,此行为不是错误。 minlength无法正常工作,因为它的设计不能够验证autofill插入的值。在下面阅读更多内容。
minlength为什么不起作用?

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

If an element has a minimum allowed value length, its dirty value flag is true, its value was last changed by a user edit (as opposed to a change made by a script), its value is not the empty string, and the JavaScript string length of the element's API value is less than the element's minimum allowed value length, then the element is suffering from being too short.



显而易见,只有通过用户编辑而不是通过脚本更改了值,才可以通过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;
}
<input type="text" minlength="5">


您可以看到,当脚本将input的值更改为“Test”时,便无需麻烦验证它。

使用pattern
另一方面,pattern没有约束验证,表明必须由用户编辑来更改值。您可以阅读有关其constraint validation here的信息。因此,您仍然可以使用脚本来更改input的值,并且该脚本仍将起作用。尝试再次向input输入“测试”:

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


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

这是一个使用pattern的解决方案,通过一些调整来验证input给出的autofill:

* {
  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的信息。

关于javascript - CSS自动填充和验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60456590/

相关文章:

Javascript:虽然变量在全局范围内声明,但在函数内部仍未定义

javascript - 无法使用 Backbone.js 将数据保存到 localStorage

javascript - 导航栏菜单位置和悬停

javascript - 给定依赖项列表,如何将 Dojo 构建到单个文件中?

html - 如何保持元素菜单的高亮

html - 可以在圆形区域的那个位置创建很多 `div` 吗?

html - CSS 语音气球宽度

html - 仅将元素移动到具有负边距的左侧,但元素也会移动到顶部

html - 链接之前有效,但在最近更新后它失败了?

html - 如何在 Firefox 中使用 CSS 为用户选择的选项着色