How to disable auto-fill in Safari 7

2020-02-09 01:32发布

问题:

I'm trying to find a way to make Safari 7 (tested with version 7.0.2, 7.0.3) respect the autocomplete="off" attributes. No matter what I try, it continues to auto-fill.

This is a problem for one of our admin pages where we set up new users. Our users keep saving over with their own username/password.

Here's an abbreviated version of the form we're using. I've tried renaming the fields to "xxu" and "xxp" but the autofill seems to read the label caption. I've fooled with various different labels but it still somehow triggers the auto-fill.

<form novalidate autocomplete="off">
     <div class="control-group">
          <label class="control-label">Username</label>
          <div class="controls">
               <input type="text" name="xxu" autocomplete="off" required="required">
        </div>
     </div>
     <div class="control-group">
          <label class="control-label">Username</label>
          <div class="controls">
               <input type="password" name="xxp" autocomplete="off" required="required">
        </div>
     </div>
</form>

I found this article on Apple's site that describes this problem. https://discussions.apple.com/message/25080203#25080203

Does anyone know of any other method for disabling auto-fill for a form in Safari 7? (Agh, this is the kind of thing we'd expect from IE)

Thanks for the help.

回答1:

We had the same problem recently. On top of that, we had a AJAX validation of our form happening onBlur. For some strange reason, this would trigger safari to autofill our email input field again. So every time you fill in the email that you want, Safari would fill in an email that it preferred instead. Making it impossible to go through our form.

Our solution

was to pretty much break Safaris (and Chromes) autofill algorithm.

HTML:

<div class="douchebag_safari">
    <input class="js-clear_field" tabindex="-1" name="e-mail" type="email">
    <input class="js-clear_field" tabindex="-1" name="Ecom_User_Password" type="password">
</div>

CSS:

.douchebag_safari {
    position: fixed;
    width: 1px;
    left: -50px;
}
.douchebag_safari input {
    width: 1%;
}

JS:

$('#form').on('submit', function () {
    "use strict";
    $('.js-clear_field').attr('disabled', 'disabled');
}

The jist of it is: We put input fields of type email and password with names that will rank higher (or same?) in Safaris autofill algorithm and hide them outside the screen. OnSubmit, the fields will be disabled and will thus be excluded from the POST to our backend.

The downside is that users won't have autocomplete on our form, but we decided that it was worth it in our case.

NOTE (assuming you care): Users with Javascript disabled will still get these fields included in their POSTs. Depending on your setup, you will need to allow these two fields to come through to your backend to prevent errors. Just make sure you don't do anything with these fields for security reasons!

As a bonus, this solved a bug where Chrome (35) assumed the input field above the password field is the username. In our case, it was a number field, giving strange user experience and bugs.



回答2:

I went with a simplified variation of the douchebag_safari approach that @Skurpi came up with. It's HTML only and goes at the bottom of my form.

<!-- http://stackoverflow.com/questions/22817801/how-to-disable-auto-fill-in-safari-7 -->
<div class="douchebag_safari" style="left: -9999px; position: fixed; width: 1px;">
    <input type="password">
</div>


回答3:

I found a quicker and simple way to avoid the form autocompleting. It works in FF 27, Chrome 36 and Safari 7.0.5 on a Mac. I still have not tested it in other OS.

I simply put a fake field as the first place in my form, no need for label or id and name attributes. I hid it for instance with an inline style and voilà!

<input type="password" style="display: none">

The email and password fields in my form are filled with the values from the database as expected and not getting autocompleted anymore.

To be honest, I don't like this solution either... I would love to find a compatible and standard solution but seems that autocomplete="off" is not working anymore.



回答4:

Had the same issue and tried the first two HTML / CSS only solutions mentioned.

They did not work for me (or Safari 9.0.3 :) ) so I implemented a solution like this

<div style="overflow: hidden;width: 0px;height: 0px;">
  <input id="password" type="password" name="password" />
</div>

on top of the actual form input fields.

Tested on Safari, Firefox (44.0.2) and Chrome (48.0.2564.109) running on OS X El Capitan.



回答5:

I used a random number and incorporated it into each field name so that the browser never recognized the name of the field.



回答6:

The solutions given above did not work for me. After investigation I could evaluate that Safari's decision to enable autofill relies on the following factors:

  • Does the "id" attribute of the input contain "name"?
  • Does the "name" attribute of the input contain "name"?
  • Does the label of the input contain "name"?

I could then disable Safari's autofill with the following code, that I ended with wrapping it into a jQuery plugin, for convenience:

$(document).ready(function () {
	$('input').disableAutoFill();
});

(function($) {

	$.fn.disableAutoFill = function() {

		"use strict";

		var self = {

			/**
			 * Disable autofill for one input
			 * @param {Object} $input jQuery element
			 */
			disableAutoFill: function($input) {
				if (self.isBrowser('safari')) {
					self.alterLabel($input);
					self.alterName($input);
					self.alterId($input);
				}
				$input.attr('autocomplete', 'off');
			},

			/**
			 * Change input's name
			 * Make sure Safari wont detect the word "name" in the name attribute
			 * otherwise Safari will enable autofill
			 * @param {Object} $input jQuery element
			 */
			alterName: function ($input) {
				$input.attr('data-original-name', $input.attr('name'));

				// Find unique name attribute value
				var new_name = false;
				var iteration = 0;
				while (iteration < 10 && !new_name) {
					new_name = self.random();
					if (self.checkAttributeExists('name', new_name)) {
						new_name = false;
					}
				}

				if (new_name) {
					$input.attr('name', new_name);
					self.setFormSubmitHandler($input);
				}
			},

			/**
			 * Change input's id
			 * Make sure Safari wont detect the word "name" in the id attribute
			 * otherwise Safari will enable autofill
			 * @param {Object} $input jQuery element
			 */
			alterId: function ($input) {
				$input.attr('data-original-id', $input.attr('id'));

				// Find unique id attribute value
				var new_id = false;
				var iteration = 0;
				while (iteration < 10 && !new_id) {
					new_id = self.random();
					if (self.checkAttributeExists('id', new_id)) {
						new_id = false;
					}
				}

				if (new_id) {
					$input.attr('id', new_id);
					self.setFormSubmitHandler($input);
				}
			},

			/**
			 * Reset input's name and id to its initial values before submitting the form
			 * @param {Object} $input jQuery element
			 */
			setFormSubmitHandler: function ($input) {
				var $form = $input.closest('form');
				if ($form.length > 0) {
					$form.submit(function() {
						var id = $input.attr('data-original-id');
						if (id) {
							$input.attr('id', id);
						}
						var name = $input.attr('data-original-name');
						if (name) {
							$input.attr('name', name);
						}
					});
				}
			},

			/**
			 * Make sure Safari wont detect the word "name" in the label
			 * otherwise Safari will enable autofill
			 * @param {Object} $input jQuery element
			 */
			alterLabel: function ($input) {
				var $label = self.findLabel($input);
				if ($label && $label.length > 0) {
					var text = $label.text();
					var array = text.split('');
					text = array.join('<span></span>');
					$label.html(text);
				}
			},

			/**
			 * Find label element of an input
			 * see http://stackoverflow.com/questions/4844594/jquery-select-the-associated-label-element-of-a-input-field
			 * @param $input
			 * @returns {*}
			 */
			findLabel: function ($input) {
				var $label = $('label[for="'+$input.attr('id')+'"]');

				if ($label.length > 0) {
					return $label;
				}
				var $parentElem = $input.parent();
				var $parentTagName = parentElem.get(0).tagName.toLowerCase();

				if ($parentTagName == "label") {
					return $parentElem;
				}
				return null;
			},

			/**
			 * Generate a random string
			 * @returns {string}
			 */
			random: function () {
				var text = '';
				var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
				for (var i=0; i < 5; i++) {
					text += possible.charAt(Math.floor(Math.random() * possible.length));
				}
				return text;
			},

			/**
			 * Check if there is an existing DOM element with a given attribute matching a given value
			 * @param {string} attributeName
			 * @param {string} attributeValue
			 * @returns {boolean}
			 */
			checkAttributeExists: function (attributeName, attributeValue) {
				return $('['+attributeName+'='+attributeValue+']').length > 0;
			},

			/**
			 * Detect current Web browser
			 * @param {string} browser
			 * @returns {boolean}
			 */
			isBrowser: function (browser) {
				// http://stackoverflow.com/questions/5899783/detect-safari-using-jquery
				var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
				var is_explorer = navigator.userAgent.indexOf('MSIE') > -1;
				var is_firefox = navigator.userAgent.indexOf('Firefox') > -1;
				var is_safari = navigator.userAgent.indexOf("Safari") > -1;
				var is_opera = navigator.userAgent.toLowerCase().indexOf("op") > -1;
				if ((is_chrome)&&(is_safari)) {is_safari=false;}
				if ((is_chrome)&&(is_opera)) {is_chrome=false;}

				if (browser === 'chrome') {
					return is_chrome;
				}
				if (browser === 'explorer') {
					return is_explorer;
				}
				if (browser === 'firefox') {
					return is_firefox;
				}
				if (browser === 'safari') {
					return is_safari;
				}
				if (browser === 'opera') {
					return is_opera;
				}
				return false;
			}

		};

		self.disableAutoFill(this);

		return this;
	};



}(jQuery));

You can also download or check out the file here



回答7:

I've adopted a simpler solution which suits us where there are admins maintaining user accounts and occasionally setting their password, and that is simply to change the user's password input type to be:

<input type="text" name="password" />

Simple but effective.



回答8:

You can try this:

If you're able to use JavaScript and jQuery, you can place this on load of the html (body onload):

$('#theform input').val('');

This question is similar like this: Is autocomplete="off" compatible with all modern browsers?

There are browsers that no longer supports autocomplete="off"



回答9:

You can use this javascript code:

if (document.getElementsByTagName) {

var inputElements = document.getElementsByTagName(“input”);

for (i=0; inputElements[i]; i++) {

if (inputElements[i].className && (inputElements[i].className.indexOf(“disableAutoComplete”) != -1)) {

inputElements[i].setAttribute(“autocomplete”,”off”);

}

}

}


回答10:

I tried everything, got it working, and then a later version of Safari broke my website again. I am about to try the extra form fields (thanks Skurpi). In the mean time, here is my new solution (in PHP)

if(strpos($_SERVER['HTTP_USER_AGENT'],'Safari') !== false)
{
?>
    <div style="background:#ffff66;border:1px solid #ff9900;font-size:1.5em;padding:1em;">
        The Safari browser has a known bug: autocomplete replaces required data in our form with incorrect values. Unfortunately this may prevent you from adding products to the shopping cart. <br /><br />Please try a different browser or go to your browser settings and turn off autocomplete and refresh the page.
    </div>
<?php
}

If enough websites do this, maybe the Safari team will get a hint and fix their browser to obey the autocomplete="off" attribute.



标签: html safari