imageВ данной статье я бы хотел поделиться методом быстрой валидации полей с помощью разметки и стилей. Данный метод не является кроссбраузерным и рекомендуется к использованию только как дополнительная фича. По ходу статьи мы будем уменьшать наши шансы на кроссбраузерность, но повышать функциональность.

Давайте попробуем собрать стандартную форму, которая будет включать в себя: Имя, E-Mail, Телефон, Ссылку на сайт и допустим Ваш рост, чтобы поэксперементировать с числовым полем.

<form action="#" class="form">
	<input type="text" name="name" placeholder="Имя" />
	<input type="text" name="email" placeholder="E-Mail" />
	<input type="text" name="phone" placeholder="Телефон" />
	<input type="text" name="url" placeholder="Ваш сайт" />
	<input type="text" name="growth" placeholder="Ваш рост" />
	<button type="submit">Отправить</button>
</form>

HTML5


Сейчас уже никого не удивить атрибутами валидации input полей, которое принес нам стандарт HTML5. Однако, обходить стороной мы его не станем — этот метод валидации является наиболее поддерживаемым в современных браузерах.

Самый простой путь валидации — это определить тип input поля и расставить атрибуты required которые отвечают за обязательность заполнения.

<form action="#" class="form">
	<input type="text" name="name" placeholder="Имя" required />
	<input type="email" name="email" placeholder="E-Mail" />
	<input type="tel" name="phone" placeholder="Телефон" />
	<input type="url" name="url" placeholder="Ваш сайт" />
	<input type="number" name="growth" placeholder="Ваш рост" />
	<button type="submit">Отправить</button>
</form>

Применение этих двух атрибутов позволит гораздо эффективнее валидировать вводимую информацию нативными методами. Ну и конечно же поддержка этих свойств браузерами наиболее широка.

Отдельно хотелось бы сказать про тип поля tel. Ожидается что браузер будет валидировать телефонные номера, но нет, поле с типом tel используется сейчас только для автозаполнения. Дело в том, что валидация телефонных номеров очень неоднозначная задача из-за слишком большого количества различных форматов телефонных номеров в разных странах, которые просто никак не получится унифицировать и записать в одно правило.

Однако, нам на помощь приходит атрибут pattern. Этот атрибут принимает в себя значение регулярного выражения. В нашем случае рассмотрим вариант паттерна для ввода мобильного телефона в РФ: +7 (123) 456-78-91. Для этого добавим простое регулярное выражение в наше поле с телефоном, а также ограничим минимальное и максимальное количество символов:

<input type="tel" name="phone" placeholder="Телефон"  pattern="[\+]\d{1}\s[\(]\d{3}[\)]\s\d{3}[\-]\d{2}[\-]\d{2}" minlength="18" maxlength="18" />

Обычно я использую данный паттерн в связке с маской для ввода номера, но тут к сожалению без JS пока что не обойтись. Если вы не используете маску, то я бы не стал использовать паттерны на вводе телефона, поскольку это в большинстве случаев вызовет больше неудобств для пользователя.

Поддержка браузерами атрибута pattern на данный момент очень хорошая. iOS начиная с версии 10.3 полностью поддерживает данное свойство, до этого наблюдалось отсутствие подсказок о неправильном вводе данных.

Стоит также учитывать, что атрибут minlength до сих пор не поддерживается в браузерах IE, EDGE и только с версии 10.3 появился в iOS. Однако maxlength поддерживается везде и очень давно. Нам в целом хватит и этого.

Давайте также поставим ограничение для поля с ростом. Допустим мы предполагаем, что пользователь нашего сайта определенно не может быть ниже 100 см и выше 250 см. Так и напишем:

<input type="number" name="growth" placeholder="Ваш рост" min="100" max="250" />

С поддержкой этих атрибутов в браузерах, все хорошо.

Перейдем к стилизации!

CSS3


Для того чтобы кастомно стилизовать нашу валидацию, воспользуемся псевдоклассами :invalid и :valid. Поддержка этих псевдоклассов в браузерах позволяет использовать их максимально широко на данный момент.

input:invalid {border-color: red;}
input:valid {border-color: green;}

Казалось бы, берем полученные знания и применяем! Но не все так просто как кажется, давайте проверим как это работает. В результате мы получим, что все наши поля изначально пустые и обязательные будут считаться не валидными, а все остальные валидными. Совсем не красиво и непонятно для пользователя, что от него хотят.

Мы можем пойти на небольшую хитрость и использовать псевдокласс :placeholder-shown. С помощью этого псевдокласса мы можем определить отображается ли сейчас значение placeholder в нашем поле ввода. Атрибут placeholder отображается только тогда, когда в наше поле ничего не введено. Соответственно, чтобы применить этот псевдокласс нам просто нужно обратить его свойство с помощью :not. В итоге получаем вот такую конструкцию:

input:invalid:not(:placeholder-shown) {border-color: red;}
input:valid:not(:placeholder-shown) {border-color: green;}

Если прочитать дословно: окрасить красным цветом границу инпута, когда наше поле не валидно и когда в нем не отображается значение атрибута placeholder. Если ваше поле не имеет атрибута placeholder, можно просто поставить внутри пробел:

<input type="text" placeholder=" " />

У данного метода есть только один минус: поддержка. Псевдоэлемент :placeholder-shown поддерживается во всех браузерах кроме IE и EDGE. К счастью :not не обладает таким недостатком.

Для примера я набросал все вышесказанное в CodePen и добавил еще немного возможностей:



Итог


Таким образом, не прибегая к JS мы с помощью двух строк в CSS смогли стилизовать и валидировать форму. На текущий момент такая конструкция будет хорошо работать в большинстве браузеров, к сожалению, как всегда, веб-разработку подводят детища Microsoft.
Поделиться с друзьями
-->

Комментарии (42)


  1. Aingis
    10.07.2017 18:30
    +6

    К сожалению, при таком использовании :valid срабатывает сразу как будет только введён хоть один символ, что плохо с точки зрения пользовательского опыта. А <input type="url"> крайне неудобен тем, что требует обязательного указания протокола http: (https:), просто домен, как в адресной строке браузера, там не написать. Роботы должны делать удобную жизнь людям, а не наоборот.


    Лучше на тему браузерной валидации форм почитать трилогию PPK: «Native form validation» (part 2, part 3)


    1. Aingis
      11.07.2017 12:58
      +1

      Кстати, недавно появилось видео хорошего доклада по теме валидации:



  1. iXCray
    10.07.2017 18:33
    +3

    Можно, конечно, назвать это придиркой, но все же:


    image


    Это хороший пример, который показывает, что для сложной и действительно удобной для пользователя (а мы работаем на удовольствие наших пользователей), связка pattern+CSS является так себе средством.


    А когда мы учтем все необходимые требования к каждому полю, а также (sic!) зависимости между полями, pattern будет неподъемным для понимания по сравнению с парой удобных функций JS.


    1. vUdav
      11.07.2017 14:14

      Согласен, пример с вводом телефона сложен для валидации, именно поэтому я указал в статье, что я обычно в этом случае все таки прибегаю к маске ввода с помощью JS плагина. Если мы говорим именно о простой валидации которую можно сделать быстро, из личного опыта могу сказать, что использование паттерна + плагина jQuery Mask Plugin написать быстрее. Однако, цель тут была показать возможности использования атрибута pattern и его реакцию на псевдоклассы.


    1. romankonstant
      11.07.2017 14:14
      +1

      Тю! Будьте аккуратны: на мобильной клавиатуре iOS по типу tel нет ни скобочек ни пробелов — потому если вы сделаете как предлагает ТС, то вы нахрен убьете часть пользователей, тк с мобильных эту форму невозможно заполнить.


      Соответственно надо делать что-то иное.


      1. vUdav
        11.07.2017 14:17

        Спасибо, не знал про такую особенность iOS. Опять же, маска спасает, если мы говорим о номере телефона


  1. Akuma
    10.07.2017 20:40
    +6

    Таким образом, не прибегая к JS мы с помощью двух строк в CSS смогли...

    … подпортить нервы незадачливому пользователю, попавшему на наш сайт.

    Ну правда. Не хочу обидеть автора, т.к. при неимении JS это отличный вариант, вот только кто сейчас сидит без JS? Я и 5 лет назад таких не видел в реальной жизни, а сейчас его отключают либо специально и сознательно, либо у них не работает абсолютно ничего. Давайте будем ориентироваться на реальных пользователей и предоставлять им удобные маски, подсказки «по проверке», а не при первом символе и возможность ввести ссылку без протокола.

    Если вам так хочется сделать валидацию без JS, просто отпраляете форму и рендерите ошибки на стороне сервера. Там можно и телефон в порядок привести (79181234567 вполне себе валиден) и ссылке приписать протокол (google.ru и https://google.ru/ не отличает 99.9% пользователей).


    1. zhanbst
      11.07.2017 14:18
      -1

      … от рендеривать на стороне сервера… только вот данные будем туда сюда елозить ). Лучше уж через JS, а точнее готовое Inputmask.js использовать


      1. ArVaganov
        11.07.2017 18:10

        Имхо, нужно всегда делать валидацию на сервере вдобавок к валидации на клиенте.
        Просто с точки зрения безопасности.


  1. Apx
    10.07.2017 21:48
    +2

    Это пример уровня hello world. Реалии таковы что в боевых условиях js must have. Conditional validation когда валидность проверяется в купе с другими полями никак не сделать кроме как на js.


  1. Alexeyco
    11.07.2017 02:01

    Не, а вот смотрите. К примеру, SPA приложение взять. Вы же все равно на бэкенде будете валидировать. Ну как ни крути, все равно же делать. Я согласен, может и не очень трудозатратно, но с моей точки зрения выглядит странновато тратить время на такое. Тем более, что вот, например, начал вводить я свой электронный адрес, а мне прямо сразу бац — ошибку. Меня это в IDE временами раздражает. И тут возникли схожие ощущения. Как будто хлыстом подгоняют. А если вы на бэкенде будете валидировать, то это будет актуально для отправки формы, которое случается после заполнения формы полностью.


    1. fsou11
      11.07.2017 08:48
      +1

      Валидация на backend не отменяет необходимость валидации данных на froentend если вам дороги серверные ресурсы. И не важно, SPA это или не SPA. Чем раньше пользователь обнаружит ошибку, тем более user-friendly окажется форма (не забываем так же и про принцип fail fast).


    1. Apx
      11.07.2017 10:36

      На бэкэнде валидировать надо чтобы умельцы всякие курлом туда мусор не гоняли как минимум :)


    1. fsou11
      11.07.2017 11:16
      -1

      Добавлю так же, что в случае с валидацией на frontend уменьшается latency и используются ресурсы клиента. Принимая во внимание, что скорость соединения так же может являться bottleneck (возьмём удалённые host'ы или 3G соединения), считаю, что валидация на клиенте это признак хорошего и зрелого приложения, нежели ненужная прихоть.


      1. Alexeyco
        11.07.2017 11:52
        -1

        Когда мы говорим о latency, мы также должны понимать, что речь идет даже не о десятых долях секунды. Признак хорошего, зрелого приложения — наличие необходимого и отсутствие лишнего. Наличие необходимого — валидация на бэкенде. А валидация на фронте лишняя уже потому, что (описал выше) она работает криво и напрямую портит пользовательский опыт. Во всяком случае, в том виде, в котором это здесь представлено.


        1. fsou11
          11.07.2017 13:56
          -1

          Говоря про latency я подразумеваю издержки на соединение посредством сети. Выше уже упоминал, что в том случае когда соединение осуществляется посредством мобильного интернета- гонять туда/сюда данные из-за нежелания реализовать валидацию на frontend, на мой взгляд, является признаком плохого тона (как с точки зрения заботы о трафике пользователя, так и времени ответа).


          1. Alexeyco
            11.07.2017 15:28
            -1

            Ну тут уж каждый выбирает сам — следовать здравому смыслу или не следовать, а реализовывать валидацию на фронте, да еще и такую, как описано в посте. Про latency на мобильных интернетах я даже слушать ничего не буду, ибо рассуждать о микросекундах при обсуждении формы авторизации (например) — это примерно такая же глупость, как то, что вы предлагаете.


    1. alix_ginger
      11.07.2017 12:47

      Тем более, что вот, например, начал вводить я свой электронный адрес, а мне прямо сразу бац — ошибку.

      Можно это починить как-то так
      input:invalid:not(:placeholder-shown):not(:focus) {border: red}
      


      1. Alexeyco
        11.07.2017 15:35

        Проблема: при вводе адреса электронной почты при первом же введенном символе поле считается заполненным с ошибкой, о чем недвусмысленно сигнализирует цветом и текстом.

        Вы: если поле теряет фокус, давайте перестанем рисовать ему красный бордер.

        Починили?


        1. justboris
          11.07.2017 17:52

          На JS починить можно, но решение из статьи тут уже не подойдет.


        1. KYuri
          11.07.2017 20:04

          Вы: если поле теряет фокус, давайте перестанем рисовать ему красный бордер.

          alix_ginger предлагает как раз обратное: когда невалидное заполненное поле теряет фокус, будем рисовать ему красный бордер.


          1. Alexeyco
            11.07.2017 21:09

            Честно признаюсь, верстальщиком не являюсь и не претендую на это. Поэтому взял JSFiddle, вставил туда указанное и увидел результат.


          1. Alexeyco
            11.07.2017 21:26

            Да, но сути-то это все равно не меняет. А вообще, если честно, каждый решает сам. Я привык (к сожалению) работать в цейтноте. Поэтому чтобы сохранить качество кода на приемлемом уровне вынужден отсекать не только все не нужное, но и то, без чего можно обойтись в принципе. Например, я лучше реализую валидацию только на бэкенде, но напишу приемочных тестов. Поэтому вот так. Может быть, если бы было побольше времени я бы и пересмотрел взгляды.


            1. KYuri
              12.07.2017 07:45

              «Необходимость» и «достаточность» — не абсолютные понятия. Они зависят от ответа на вопрос «для чего?»

              Вы описываете необходимость и достаточность для корректной работы системы (отсечь мусор). Да, необходимо и достаточно проверять данные на бэкенде, чтобы в систему не попал мусор.

              Но с точки зрения удобства пользователя этого может быть не достаточно — в качестве примера fsou11 привел работу приложения в условиях медленной сети, когда отсылка данных для проверки на сервер может занимать непредсказуемое время. Можно поиграть со стратегией проверки (либо отправлять запрос на валидацию после заполнения каждого отдельного поля, либо целиком форму), но пользователю всё равно будет неудобно.
              Для удобства пользователя валидация должна быть мгновенной, чего можно достичь только валидацией на клиенте.

              А сложности с дублированием и поддержанием эквивалентности логики на клиенте и сервере — это проблемы программиста, а не пользователя.


              1. Alexeyco
                12.07.2017 18:29

                Ну да. И ни один из вас не даст ответ на вопрос — если интернета хватило чтобы загрузить увесистый бандл SPA-приложения, то почему его не должно хватить на отправку формы? И ведь не ответите, даже если очень захотите. Но зато всегда можно завести старую песню о главном: «ехал latency через latency...».


                1. KYuri
                  12.07.2017 18:41
                  -1

                  Почему же не отвечу? Легко. Бандл легко может быть закэширован ServiceWorker-ом при первой загрузке приложения.


                  1. Alexeyco
                    13.07.2017 17:12
                    -1

                    Вы прекрасно поняли вопрос и теперь строите из себя дурачка. Все фронтэндщики одинаковые. Сначала мы выдумываем какие-то немыслимые условия, которые не существуют никогда, а потом мы делаем вид, что их героически решаем.

                    Если у пользователя настолько медленный интернет, что каждый килобайт на счету, тогда приложение не будет загружено. А раз не будет загружено — значит и потребности в валидации не возникнет. Если у пользователя быстрый, хороший интернет — то необходимости в такой экономии не возникнет.

                    Далее — мы убедились в том, что приведенное в посте решение — нерабочее. Придется реализовывать валидацию с использованием какой-то сторонней либы. Что вызовет рост размера приложения. Итого: чтобы экономить полкилобайта траффика мы подгрузим пользователю еще 30 лишних.

                    Я уже говорил, что все фронтэндщики одинаковые? Давайте лучше старую песню про «ехал latency через latency».


                    1. justboris
                      13.07.2017 17:24

                      А если нужно валидировать поля по одному, по мере заполнения формы, то вы тоже будете посылать данные на сервер?


                      Особенно это важно для удобства длинных форм, чтобы пользователь не убивал много минут на заполнение формы, а получал фидбек по мере заполнения данными.


                    1. KYuri
                      13.07.2017 18:02
                      -1

                      Давайте по порядку.

                      Вы прекрасно поняли вопрос и теперь строите из себя дурачка
                      Вопрос я понял, и дал на него ответ. А вот как раз Вы начинаете строить из себя дурачка «такой ответ не принимается, условия выдуманные».

                      В мире мобильных устройств стабильность и скорость интернета — величина непостоянная, тут выдумывать ничего не надо.

                      Хотите ещё вариант загрузки бандла при хорошей сети, и работе в приложении при плохой сети? Их есть у меня. Берем web-приложение, берем Cordova, публикуемся в стор. Пользователь дома с прекрасным вай-файем ставит наше приложение, и идёт в парк погулять. А там, сидя на лавочке, запускает наше приложение и радуется, что ничего не может сделать, потому что на каждый чих нужен сервер.

                      мы убедились в том, что приведенное в посте решение — нерабочее
                      Если кто-то забыл, то мы обсуждаем не конкретную реализацию, а вопрос, является ли достаточным и необходимым (и для чего именно) выполнять валидацию только на сервере, или она нужна и на клиенте.

                      Придется реализовывать валидацию с использованием какой-то сторонней либы. Что вызовет рост размера приложения.
                      И что? Да, вызовет. Но пользователю будет при этом удобнее.

                      Все фронтэндщики одинаковые.

                      Я уже говорил, что все фронтэндщики одинаковые?

                      Сильно удивлю, если окажусь не фронтэнщиком?


                      1. Alexeyco
                        13.07.2017 18:11

                        Господи, что за чушь только что я прочитал. На валидацию у нас интернета не хватит, а просто на отправку формы — хватит. Песенка про latency покидает наш хит-парад.


                        1. KYuri
                          13.07.2017 18:21

                          Если кто-то забыл, то мы обсуждаем не конкретную реализацию, а вопрос, является ли достаточным и необходимым (и для чего именно) выполнять валидацию только на сервере, или она нужна и на клиенте.
                          По сути обсуждаемого вопроса что-нибудь будет?

                          Господи, что за чушь только что я прочитал
                          Тогда почитайте для разнообразия про Background Sync.


  1. k12th
    11.07.2017 10:50

    Валидация это не новость. А вот попробуйте покопаться в autofill/autocomplete, вот где веселье-то.



  1. l1tero
    11.07.2017 14:34

    А это нормально, что в поле «Ваш рост» можно поставить букву «e», но другие буквы нельзя.


    1. vUdav
      11.07.2017 14:54

      Да, символ «e» или «E» является допустимым для ввода в числовое поле и обозначает следующее XeY = X+10^Y. Для примера число 2000000 можно записать как 2e6. Кстати, такую же историю можно использовать и в CSS. Правда я не знаю как хорошо это поддерживается) Хорошая тема, чтобы разобраться и написать статью.


  1. DzmitryT
    11.07.2017 14:55
    -2

    Уывжаемый аытор! Буквально месяц назад, на РИТ++ был доклад на тему вашего изыскания. Попробуйте найти видео. Там были неплохие примеры работы не только с полями, но и вцелом с формой. Еще и вывод сообщений об ошибках в родной стилизации браузера (а-ля тайтлы для элементов) прикрутить можно.


    1. vUdav
      11.07.2017 14:56

      По всей видимости речь о видео из этого комментария?


      1. DzmitryT
        11.07.2017 15:07

        Да, оно самое. Довелось присутствовать на докладе.


  1. KYKYH
    11.07.2017 14:58
    -1

    Делайте валидацию в бэкэнде, не грузите клиент-приложение бизнес-логикой. Мухи отдельно, котлеты отдельно. Аякс на все элементы ввода, запросы на валидацию всей формы, ответы в джсоне, раскидывайте нужную информацию джаваскриптом по каждому полю. Ато решите потом написать приложение-клиент для телефонов и будет у вас две валидации, и будете потом гадать, делают ли они одно и то же.


    1. vUdav
      11.07.2017 15:10
      -1

      Соглашусь, но опять же, если речь идет о простенькой форме на каком-нибудь лендинге, не вижу особого смысла заморачиваться с аякс запросами. Да, вторичная валидация строго обязательна, нельзя полагаться на клиент, но цель моей статьи была не показать как без этих ваших яваскриптов охватить весь спектр валидации форм, а о том как без особых заморочек прикрутить простенькую валидацию и как-никак стилизовать ее.

      Я рассматривал частный вариант, но часто вполне достаточный, чтобы без JS быстро валидировать форму и застилизовать ее как того пожелал дизайнер.


      1. iSm1le
        11.07.2017 20:05
        +1

        В принципе это можно использовать с поправками alix_ginger'а, чтобы не нервировать пользователя лишний раз. А вот форму с номером телефона я бы по другому реализовал бы. Например с чекбоксом выбора кода оператора, а дальше уже сам номер, но опять же в разных странах отличается.


  1. bano-notit
    12.07.2017 10:55

    Вот не ожидал, что у меня такой тупой проверщик урлов будет… Я надеялся, что хотя бы слеши запросит, а вот нифига подобного, да и после этого заветного для него "http:" можно писать что угодно, хоть скобки, хоть пробелы, хоть слеши, и ладно бы в пути, тк нет, в ДОМЕНЕ, в котором вообще-то запрещены.