Простая валидация формы без JS

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.
Share post

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 42

    +6

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


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

      +1

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


      +3

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


      image


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


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

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

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


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

            0
            Спасибо, не знал про такую особенность iOS. Опять же, маска спасает, если мы говорим о номере телефона
          +6
          Таким образом, не прибегая к JS мы с помощью двух строк в CSS смогли...

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

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

          Если вам так хочется сделать валидацию без JS, просто отпраляете форму и рендерите ошибки на стороне сервера. Там можно и телефон в порядок привести (79181234567 вполне себе валиден) и ссылке приписать протокол (google.ru и https://google.ru/ не отличает 99.9% пользователей).
            –1
            … от рендеривать на стороне сервера… только вот данные будем туда сюда елозить ). Лучше уж через JS, а точнее готовое Inputmask.js использовать
              0
              Имхо, нужно всегда делать валидацию на сервере вдобавок к валидации на клиенте.
              Просто с точки зрения безопасности.
            +2

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

            • UFO just landed and posted this here
                +1
                Валидация на backend не отменяет необходимость валидации данных на froentend если вам дороги серверные ресурсы. И не важно, SPA это или не SPA. Чем раньше пользователь обнаружит ошибку, тем более user-friendly окажется форма (не забываем так же и про принцип fail fast).
                  0

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

                    –1
                    Добавлю так же, что в случае с валидацией на frontend уменьшается latency и используются ресурсы клиента. Принимая во внимание, что скорость соединения так же может являться bottleneck (возьмём удалённые host'ы или 3G соединения), считаю, что валидация на клиенте это признак хорошего и зрелого приложения, нежели ненужная прихоть.
                    • UFO just landed and posted this here
                        –1
                        Говоря про latency я подразумеваю издержки на соединение посредством сети. Выше уже упоминал, что в том случае когда соединение осуществляется посредством мобильного интернета- гонять туда/сюда данные из-за нежелания реализовать валидацию на frontend, на мой взгляд, является признаком плохого тона (как с точки зрения заботы о трафике пользователя, так и времени ответа).
                        • UFO just landed and posted this here
                      0
                      Тем более, что вот, например, начал вводить я свой электронный адрес, а мне прямо сразу бац — ошибку.

                      Можно это починить как-то так
                      input:invalid:not(:placeholder-shown):not(:focus) {border: red}
                      
                      • UFO just landed and posted this here
                          0

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

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

                            alix_ginger предлагает как раз обратное: когда невалидное заполненное поле теряет фокус, будем рисовать ему красный бордер.
                            • UFO just landed and posted this here
                              • UFO just landed and posted this here
                                  0
                                  «Необходимость» и «достаточность» — не абсолютные понятия. Они зависят от ответа на вопрос «для чего?»

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

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

                                  А сложности с дублированием и поддержанием эквивалентности логики на клиенте и сервере — это проблемы программиста, а не пользователя.
                                  • UFO just landed and posted this here
                                      –1
                                      Почему же не отвечу? Легко. Бандл легко может быть закэширован ServiceWorker-ом при первой загрузке приложения.
                                      • UFO just landed and posted this here
                                          0

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


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

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

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

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

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

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

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

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

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

                                            Сильно удивлю, если окажусь не фронтэнщиком?
                                            • UFO just landed and posted this here
                                                0
                                                Если кто-то забыл, то мы обсуждаем не конкретную реализацию, а вопрос, является ли достаточным и необходимым (и для чего именно) выполнять валидацию только на сервере, или она нужна и на клиенте.
                                                По сути обсуждаемого вопроса что-нибудь будет?

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

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

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

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

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

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

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

                                  Only users with full accounts can post comments. Log in, please.