CSS автозаполнение и проверка - PullRequest
1 голос
/ 28 февраля 2020

Я работаю над стилизацией некоторого пользовательского ввода и наткнулся на камень преткновения.

Я ничего не имею против того, чтобы пользователь использовал автозаполнение (лично я ненавижу его, когда он отключается на некоторых сайтах), как мне кажется это действительно удобно. Я знаю, как я могу сделать это с -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

Я посмотрел этот вопрос, но пока не хочу запускать дополнительные сценарии java На этом этапе все сводится к визуальному, проверка будет позже, когда пользователь также будет взаимодействовать с другими вещами. И это проблема, если автозаполнение дает ложное представление о том, что данные действительны, на более позднем этапе может быть очень неприятно показывать их как недействительные ...

Любая идея, как это можно стилизовать из * Только 1042 *?

Если я должен использовать JS: Другая проблема заключается в том, что стиль не обновляется в поле, пока значение не будет изменено вручную, вызывая событие jQuery .change() в полях не помогает

Когда я писал вопрос, я решил немного покопаться и, что еще хуже, при автозаполнении элемент document.getElementById("first_name").checkValidity() возвращает значение true, когда это не должно.

в то время как я начал это с вопроса CSS, теперь я более склонен спросить, можно ли считать это поведение ошибкой?

Edit 1: Поскольку checkValidity() возвращает true, Я попытался отправить форму (которую обычно не следует отправлять, потому что условия проверки не соблюдаются), и она действительно прошла без каких-либо отклонений. Конечно, золотое правило применяется, никогда не доверяйте пользовательским данным, и серверная сторона отклонит их, но я думаю, что этого не должно произойти, простое автозаполнение не должно автоматически означать, что данные действительны.

Ответы [ 2 ]

3 голосов
/ 02 марта 2020

Я надеюсь, что это поможет:

использовать атрибут "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>
2 голосов
/ 03 марта 2020

Это действительно интересный вопрос. Тем не менее, мне любопытно о чем-то. Chrome будет сохранять только autocomplete значения при отправке формы (как указано здесь ). Логично, что если у ввода есть minlength из 5 и вы вводите что-то длиной 4, вы не сможете отправить форму в первую очередь . Следовательно, недопустимое значение автозаполнения не должно быть сохранено. Как вы впервые столкнулись с такой ситуацией? Я смог воспроизвести его только с помощью , а не , установив minlength, отправив, затем установив minlength и попробовав автозаполнение.

Чтобы ответить на ваш вопрос, это поведение не является ошибкой. minlength не работает, потому что он не предназначен для проверки значений, вставленных autofill. Подробнее читайте ниже.

Почему minlength не работает?

Почему minlength не делает недействительными значения, заданные autocomplete, когда длина значений меньше указанной minlength? Упомянутый в стандарте HTML от WHATWG , minlength имеет проверку этого ограничения:

Если элемент имеет минимально допустимую длину значения, его флаг «грязное» значение имеет значение true, его значение в последний раз изменялось пользователем (в отличие от изменения, выполненного сценарием), его значение не является пустой строкой, а длина строки JavaScript значения API элемента меньше минимально допустимой длины значения элемента , тогда элемент страдает от слишком короткого.

Становится очевидным, что значение будет проверено minlength только тогда, когда его значение было изменено редактированием пользователя , а не по сценарию. Читая далее, мы можем сделать вывод, что значения autofill вставляются скриптом (читайте здесь ). Мы можем проверить minlength не проверяя значения ввода, когда они изменяются скриптом, выполнив следующее (пожалуйста, вставьте слово «Проверка» во вход):

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, с другой стороны, не имеет проверки ограничения, говоря, что значения должны быть изменены путем редактирования пользователем. Вы можете прочитать о проверке ограничения здесь . Поэтому вы все равно можете изменить значение 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,}">

Когда оно меняется на «Тест», оно становится недействительным на 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 и о том, как его лучше использовать здесь .

...