我遇到了chrome自动填充行为的几个形式的问题。

表单中的字段都有非常常见和准确的名称,例如“email”、“name”或“password”,并且它们还设置了autocomplete=“off”。

自动完成标志已经成功禁用了自动完成行为,当你开始输入时,会出现一个下拉的值,但没有改变Chrome自动填充字段的值。

这种行为是可以的,除了chrome填充输入不正确,例如填充电话输入与电子邮件地址。客户抱怨过这个问题,所以它被证实在很多情况下都发生了,而不是我在我的机器上本地操作的某种结果。

目前我能想到的唯一解决方案是动态生成自定义输入名称,然后在后端提取值,但这似乎是一种相当笨拙的解决这个问题的方法。是否有任何标签或怪癖,改变自动填充行为,可以用来解决这个问题?


当前回答

2022年4月:autocomplete="off"仍然不能在Chrome中工作,我不相信在查看了与此问题相关的Chromium bug后(可能只针对密码字段)。我看到2014年报告的问题被关闭为“WontFix”,问题仍然悬而未决,正在讨论[1][2]。据我所知,Chromium团队不相信有一个有效的用例autocomplete="off"。

总的来说,我仍然认为这两种极端策略(“总是尊重自动完成=关闭”和“从不尊重自动完成=关闭”)都是不好的。

https://bugs.chromium.org/p/chromium/issues/detail?id=914451#c66

他们的印象是,网站不会正确使用它,并决定不应用它,提出以下建议:

In cases where you want to disable autofill, our suggestion is to utilize the autocomplete attribute to give semantic meaning to your fields. If we encounter an autocomplete attribute that we don't recognize, we won't try and fill it. As an example, if you have an address input field in your CRM tool that you don't want Chrome to Autofill, you can give it semantic meaning that makes sense relative to what you're asking for: e.g. autocomplete="new-user-street-address". If Chrome encounters that, it won't try and autofill the field.

https://bugs.chromium.org/p/chromium/issues/detail?id=587466#c10

虽然这个“建议”目前对我来说是可行的,但它可能并不总是正确的,看起来团队正在进行实验,这意味着自动完成功能可能会在新版本中改变。

我们不得不求助于这个是愚蠢的,但唯一可靠的方法是尽可能地迷惑浏览器:

在不向浏览器泄露任何信息的情况下为输入命名,例如id="field1"而不是id="country"。 设置autocomplete="do-not-autofill",基本上使用任何不会让浏览器识别为可自动填充字段的值。


2021年1月:autocomplete="off"现在按预期工作(在Chrome 88 macOS上测试)。

要做到这一点,请确保input标记位于Form标记中


2020年9月:autocomplete=" Chrome -off"禁用Chrome自动填充功能。


原答案,2015年:

对于新版本的Chrome浏览器,你只需要在密码栏中输入autocomplete="new-password"就可以了。我检查过了,工作正常。

在这次讨论中,我从Chrome开发者那里得到了一个建议: https://bugs.chromium.org/p/chromium/issues/detail?id=370363#c7

P.S. Note that Chrome will attempt to infer autofill behavior from name, id and any text content it can get surrounding the field including labels and arbitrary text nodes. If there is a autocomplete token like street-address in context, Chrome will autofill that as such. The heuristic can be quite confusing as it sometimes only trigger if there are additional fields in the form, or not if there are too few fields in the form. Also note that autocomplete="no" will appear to work but autocomplete="off" will not for historical reasons. autocomplete="no" is you telling the browser that this field should be auto completed as a field called "no". If you generate unique random autocomplete names you disable auto complete.

如果你的用户访问了不好的表单,他们的自动填充信息可能会被损坏。让他们手动进入并修复Chrome中的自动填充信息可能是他们采取的必要行动。

其他回答

以下是我提出的解决方案,因为谷歌坚持推翻人们似乎做出的每一个变通办法。

选项1 -选择所有文本点击

为你的用户设置输入的值为一个例子(例如your@email.com),或者字段的标签(例如Email),并在你的输入中添加一个名为focus-select的类:

<input type="text" name="email" class="focus-select" value="your@email.com">
<input type="password" name="password" class="focus-select" value="password">

下面是jQuery:

$(document).on('click', '.focus-select', function(){
  $(this).select();
});

我真的看不出Chrome会搞砸数值。那太疯狂了。希望这是一个安全的解决方案。

选项2 -设置电子邮件值为一个空间,然后删除它

假设您有两个输入,例如电子邮件和密码,将电子邮件字段的值设置为“”(一个空格),并添加属性/值autocomplete=“off”,然后使用JavaScript清除此设置。您可以将密码值保留为空。

如果用户出于某种原因没有JavaScript,请确保您在服务器端修改了他们的输入(无论如何您都应该这样做),以防他们不删除空格。

下面是jQuery:

$(document).ready(function() {
  setTimeout(function(){
    $('[autocomplete=off]').val('');
  }, 15);
});

我将超时设置为15,因为5似乎在我的测试中偶尔可以工作,所以将这个数字增加三倍似乎是一个安全的赌注。

如果没有将初始值设置为空格,Chrome会让输入框显示为黄色,就好像它已经自动填充了一样。

选项3 -隐藏输入

把这个放在表单的开头:

<!-- Avoid Chrome autofill -->
<input name="email" class="hide">

CSS:

.hide{ display:none; }

确保您保留了HTML注释,这样其他开发人员就不会删除它!还要确保隐藏输入的名称是相关的。

唯一适合我的方法是:(jQuery要求)

$(document).ready(function(e) {
    if ($.browser.webkit) {
        $('#input_id').val(' ').val('');
    }
});

Finally I think I came with a decent solution. Understanding better how the dropdown works with Chrome helped :) Basically, the dropdown will be displayed when you focus the input and when you generate a mouse down event when you are typing an entry which matches with what Chrome has in memory. Keeping that in mind, and that Chrome does it for certain inputs when they have default names like "name", "email", etc. then we just need to remove the name when the dropdown is going to be displayed and add it back after :) I wanted to use a solution which can make it work just by adding the attribute autocomplete off. I thought it made sense. This is the code:

解决方案1

jQuery('body').on('mousedown','[name="name"][autocomplete="off"], [name="email"][autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    if(typeof this.currentName =="undefined")
        this.currentName=jQuery(this).attr('name');
    jQuery(this).attr('name','');
});

jQuery('body').on('blur','[autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    jQuery(this).attr('name',this.currentName);
});

解决方案2(我最喜欢的一个)

The solution I described above will remove the name of the input until we remove the focus (blur), in that moment it will put the original name back. But might happen that we are interested on having access to the input through its name attribute while we are typing. Which means that we need to put the name back right after each input. This solution, basically is based on the first solution. In this case, we will add the name on key down, and put it back on keyup. I think this is more neat for compatibility with what the "autocomplete off" behaviour should be. Anyway this is the code:

jQuery('body').on('mousedown keydown','[name="name"][autocomplete="off"], [name="email"][autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    if(typeof this.currentName =="undefined")
        this.currentName=jQuery(this).attr('name');
    jQuery(this).attr('name','');
});
jQuery('body').on('blur keyup','[autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    if(typeof this.currentName !="undefined")
        jQuery(this).attr('name',this.currentName);
});

请注意,对于解决方案1和2,我只采用输入名称为“name”和“email”的情况。对于任何其他情况下,这个属性使Chrome生成下拉,你将不得不添加它在选择器的鼠标下拉事件。

解决方案3

这个解决方案要复杂得多。我没有意识到我们试图纠正的行为只是基于那些带有特定名称的输入,如“姓名,电子邮件等”。这种解决方案的方法是在这种情况下,Chrome显示的其他名称,我们不知道一个先验。这将是一个非常通用的解决方案。我不像其他两个那样喜欢,主要是因为当我们按下删除键时,可能会有一个小闪烁。我会在下面解释。

我发现,下拉框出现在第二次点击输入后,而不是第一次点击时,当你第一次聚焦在输入上时。我为所有这些元素绑定了一个“mousedown”事件,其中处理程序基本上检测它是否已经聚焦在输入上,如果它检测到另一个“鼠标向下”,强制一个.blur(),然后是.focus(),防止第二次点击时的下拉。我希望,这是清楚的,以防万一,这是我使用的代码:

jQuery('body').on('mousedown','[autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    if(jQuery(this).is(':focus')) {
        jQuery(this).blur();
        jQuery(this).focus();
    }
});

In the other hand, in order to prevent the dropdown while you are typing in case it matches with Chrome suggestions... This is a little bit tricky. I just decided to replace the default behaviour of an input while user types. The dropdown evaluates the input on mouse down, so I prevent the default behaviour for alphanumerics, space, etc. The only problem is with Command,Ctrl and delete. For this case I had to bind also an event on mouse up. It allows the default behaviour in the first two cases so you can make copy, and paste, or select all. In the case of the delete, I have to allow the default behaviour, but if after deleting a character the input matches with Chrome suggestions, then again it was showing the dropdown. For this case I had to use the same trick of blur and focus. The only inconvenience I found on this is that since we are cancelling the behaviour on keyup, and chrome tries to show it on keydown, there is a small flicker. Anyway, this is the best I could do. Probably it will require for filtering of characters at one point. I just added the conditions made more sense for now. This is the second part of the code:

jQuery('body').on('keydown','[autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    var ctrlKey = 17,cmKey = 91;
    var charCode = e.which || e.keyCode;

    if(charCode!=16 && this.commandDown != true && this.ctrlDown != true && ((charCode>47 && charCode<58)||(charCode>64 && charCode<91)||(charCode>96 && charCode<123)||charCode==0 || charCode==32)){ 
        e.preventDefault();
        var charStr = String.fromCharCode(charCode);
        if(!e.shiftKey)
            charStr = charStr.toLowerCase(charStr);
        $(this).val($(this).val() + charStr);
    }else{
        if (charCode == cmKey) this.commandDown = true;
        if (charCode == ctrlKey) this.ctrlDown = true;
    }
});
jQuery('body').on('keyup','[autocomplete="off"]',function(e){
    e.stopImmediatePropagation();
    var allowed=[8];//Delete
    var ctrlKey = 17,cmKey = 91;
    var charCode = e.which || e.keyCode;

    if (charCode == cmKey) {this.commandDown = false};
    if (charCode == ctrlKey) {this.ctrlDown = false};
    if(allowed.indexOf(charCode)>=0 || (this.commandDown!=false && this.ctrlDown!=false)){
        jQuery(this).blur();
        jQuery(this).focus();
}

就像我说过的,这个解要复杂得多。这是我使用的第一个,直到我意识到下拉列表只出现在某些输入名称上。

抱歉写了这么多,我只是想确保一切都清楚。我希望这能有所帮助。

我刚刚发现,如果你记住了一个网站的用户名和密码,当前版本的Chrome会自动填充你的用户名/电子邮件地址到任何type=password字段之前。它并不关心字段被称为什么-只是假设password之前的字段将是您的用户名。

旧的解决方案

只要使用<form autocomplete="off">,它就可以防止密码预填充以及基于浏览器可能做出的任何类型的启发式填充字段(这通常是错误的)。而不是使用<input autocomplete="off">,这似乎被密码自动填充忽略了(在Chrome中,Firefox确实遵守它)。

更新的解决方案

Chrome现在忽略<form autocomplete="off">。因此,我最初的解决方案(我已经删除了)现在非常流行。

简单地创建两个字段,并使用“display:none”隐藏它们。例子:

<!-- fake fields are a workaround for chrome autofill getting the wrong fields -->
<input style="display: none" type="text" name="fakeusernameremembered" />
<input style="display: none" type="password" name="fakepasswordremembered" />

然后把你真正的领域放在下面。

记得添加评论,否则你团队中的其他人会想知道你在做什么!

2016年3月更新

刚刚测试了最新的Chrome -一切都很好。这是一个相当古老的答案,但我想说的是,我们的团队已经在几十个项目中使用它很多年了。尽管下面有一些评论,但它仍然很好用。可访问性没有问题,因为字段是显示的:无意味着它们不会得到焦点。正如我提到的,你需要把它们放在你真正的领域之前。

如果使用javascript修改表单,还需要一个额外的技巧。在操作表单时显示假字段,然后在一毫秒后再次隐藏它们。

使用jQuery的示例代码(假设你给你的假字段一个类):

$(".fake-autofill-fields").show();
// some DOM manipulation/ajax here
window.setTimeout(function () {
  $(".fake-autofill-fields").hide();
}, 1);

2018年7月更新

我的解决方案不再那么有效,因为Chrome的反可用性专家已经在努力工作。但他们给了我们一点好处:

<input type="password" name="whatever" autocomplete="new-password" />

这很有效,基本上解决了问题。

但是,当您没有密码字段而只有电子邮件地址时,它将不起作用。这也很难让它停止变黄和预填充。可以使用假字段解决方案来修复这个问题。

事实上,有时您需要放入两个假字段,并在不同的地方尝试它们。例如,我已经在我的表格的开头有假字段,但Chrome最近又开始预填充我的“电子邮件”字段-所以我加倍努力,在“电子邮件”字段之前放了更多的假字段,这就解决了问题。删除第一批或第二批字段将还原为不正确的过度自动填充。

更新 Mar 2020

目前尚不清楚这种解决方案是否以及何时仍然有效。它似乎有时仍然有效,但不是一直有效。

在下面的评论中,你会发现一些提示。@anilyeni刚刚添加的一个可能值得更多的研究:

正如我注意到的,autocomplete="off"在Chrome 80上工作,如果<form>中少于三个元素。我不知道它的逻辑是什么,也不知道它的相关文档在哪里。

还有来自@dubrox的这个可能是相关的,尽管我还没有测试过:

非常感谢你的技巧,但请更新答案,如下所示:无;不再工作,但位置:固定;顶部:-100px;左侧:-100px;宽度:5 px;:)

2020年4月更新

chrome的特殊值为这个属性正在做的工作:(在输入上测试-但不是由我) 自动完成= " chrome-off "

除了autocomplete="off"外,还必须将值设置为空(value="")才能使其工作。