имя ключа параметра. Для поля поиска чаще всего применяется «q» или «text». значение ключа параметра. Чаще всего не задаётся. Пользователь может его изменить на свой текст, если не указаны атрибуты readonly и disabled . заблокировано изменение пользователем заблокированы доступ, изменение пользователем и передача данных текущего параметра поле не может быть пустым шаблон ввода как в регулярных выражениях JS , следование которому необходимо для отправки формы минимальное количество символов, необходимое для отправки формы максимальное количество символов, которое может набрать пользователь длина поля в символах подсказка-заглушка всплывающая подсказка при наведении курсора мышки автозаполнение. Современные браузеры показывают ранее введённые поисковые запросы на текущем домене. Можно его отключить или сделать более конкретизированным. список рекомендованных запросов проверяется орфография и грамматика фокус поля (то есть период между щелчком по элементу и щелчком вне элемента) получен при загрузке документа

Убрать в поле поиска крестик «Очистить», удаляющий ранее набранный текст

Как работает форма поиска на сайте

Самый простой HTML-код

Если набрать в поле «вопрос» и щелкнуть по кнопке «Найти», то адрес страницы изменится с « http://сайт/2011/06/forma-poiska-po-saitu..html?text=вопрос », как это происходит при нажатии на ссылку . При загрузке страницы, скрипт проверяет наличие заданных параметров в URL и при их обнаружении формирует и отображает результаты поиска по сайту.

name="text" >

Но в целях увеличения скорости загрузки документа, скрипт, обрабатывающий запрос, как правило, помещают только на одну страницу сайта, на которую будет сделан переход, если её адрес прописать в атрибуте action: « http://сайт/search/ ?text=вопрос ».

action="http://сайт/search/" >

Для работы скрипта могут понадобиться дополнительные параметры, которые указываются в . Это поле не отображается.?searchid=808327 &text=вопрос ».

Результат работы формы открыть в новой вкладке с помощью атрибута target

target="_blank" >

Где взять скрипт поиска по сайту

Можно воспользоваться

  • предложенным специальными сервисами Яндекса и Google ,
  • встроенным в используемую CMS (при наличии), например, на Blogger на « https://site.ru /search?q=вопрос », где « site.ru » заменить на свой адрес блога,
  • разработанным самостоятельно, например, на PHP.

Самый простой вариант - перенаправить запрос Google:

Текст на кнопке: «Поиск», «Искать», «Найти»

Из слов-побудителей «Найти» имеет совершённый вид и подразумевает, что результат поиска будет обязательно положительным.

Эта заметка является продолжением предыдущей статьи (перевода) "Поиск для блога с помощью Google AJAX Search API и jQuery ".
После её написания я задумался о том, где будет удачнее всего расположить такую форму и ковёр результатов, кроме отдельной страницы. Идея не заставила себя долго ждать: логично попробовать поиск с результатами во всплывающем окне.

Сначала демка :

Поиск по блогу↓

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

Установка Reveal .
В секцию шаблона прописываются линки на скрипт и стили:
Не забудьте, что в архив плагина есть картинка png, которую нужно положить в свой альбом пикасы и прописать путь к ней в reveal.css .

Следущий шаг - инициализировать плагин "настроечным " скриптом (кладём туда же):

Потом определяем содержимое всплывшего окна (это кладём в тело поста):

Поиск по блогу↓

сюда вставляем все коды поиска из статьи "Поиск для блога с помощью Google AJAX Search API и jQuery".

Согласно моему комментарию внутри этого кода, копипастим туда весь "гуглопоиск" , о котором идёт сейчас речь. В шаблоне стилей css придётся увеличить площадь белого квадрата.

И последний шаг - сама ссылка на модальное окно , которая может быть как текстовой, так и графической. Код ссылки в виде картинки (тоже в тело поста):

У Reveal , плагина модальных окон, есть два вида анимации: fade и fadeAndPop , регулируемая скорость выполнения эффекта: animationspeed: 300 , и возможность закрыть всё окно, кликнув по затемнённому фону: closeonbackgroundclick: true .

Эти настройки записываются в "настроечный" скрипт (см. выше):

$("#myModal").reveal({ animation: "fadeAndPop", //fade, fadeAndPop, none animationspeed: 300, //how fast animtions are closeonbackgroundclick: true, //if you click background will modal close? dismissmodalclass: "close-reveal-modal" //the class of a button or element that will close an open modal });

Или же эти опции можно подключать через ссылку на модальное окно (см. выше)

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

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

В этом уроке вы узнаете, как создать разметку для поля поиска с помощью HTML5, а также как стилизовать элементы формы, используя возможности CSS3, без использования скриптов.

1. Разметка HTML

Элемент

является контейнером для формы поиска, поле поиска создается при помощи элемента или , а кнопка отправки данных на сервер может создаваться с помощью элемента или
* {box-sizing: border-box;} form { position: relative; width: 300px; margin: 0 auto; } input { width: 100%; height: 42px; padding-left: 10px; border: 2px solid #7BA7AB; border-radius: 5px; outline: none; background: #F9F0DA; color: #9E9C9C; } button { position: absolute; top: 0; right: 0px; width: 42px; height: 42px; border: none; background: #7BA7AB; border-radius: 0 5px 5px 0; cursor: pointer; } button:before { content: "\f002"; font-family: FontAwesome; font-size: 16px; color: #F9F0DA; }

3. Поле поиска с кнопкой внутри

* {box-sizing: border-box;} form { position: relative; width: 300px; margin: 0 auto; } input, button { border: none; outline: none; border-radius: 3px; } input { width: 100%; height: 42px; background: #F9F0DA; padding-left: 15px; } button { height: 26px; width: 26px; position: absolute; top: 8px; right: 8px; background: #F15B42; cursor: pointer; } button:before { content: "\f105"; font-family: FontAwesome; color: #F9F0DA; font-size: 20px; font-weight: bold; }

4. Поле поиска в стиле «flat»

* {box-sizing: border-box;} form { position: relative; width: 300px; margin: 0 auto; background: #A3D0C3; } input, button { border: none; outline: none; background: transparent; } input { width: 100%; height: 42px; padding-left: 15px; } button { height: 42px; width: 42px; position: absolute; top: 0; right: 0; cursor: pointer; } button:before { content: "\f002"; font-family: FontAwesome; font-size: 16px; color: #F9F0DA; }

5. Поле поиска с толстой нижней границей

* {box-sizing: border-box;} form { position: relative; width: 300px; margin: 0 auto; background: #F9F0DA; border-bottom: 4px solid #be290e; } input, button { border: none; outline: none; background: transparent; } input { width: 100%; height: 42px; padding-left: 15px; } button { height: 42px; width: 42px; position: absolute; top: 0; right: 0; cursor: pointer; } button:before { content: "\f178"; font-family: FontAwesome; font-size: 20px; color: #be290e; }

6. Поле поиска с меняющимся цветом границы

* {box-sizing: border-box;} form { position: relative; width: 300px; margin: 0 auto; } input, button { outline: none; background: transparent; } input { width: 100%; height: 42px; padding-left: 15px; border: 3px solid #F9F0DA; } button { border: none; height: 42px; width: 42px; position: absolute; top: 0; right: 0; cursor: pointer; } button:before { content: "\f002"; font-family: FontAwesome; font-size: 16px; color: #F9F0DA; } input:focus { border-color: #311c24; }

7. Выезжающее поле поиска

Поле поиска появляется при нажатии на кнопку с иконкой.

* {box-sizing: border-box;} form { position: relative; width: 300px; margin: 0 auto; height: 42px; } input { height: 42px; width: 0; padding: 0 42px 0 15px; border: none; border-bottom: 2px solid transparent; outline: none; background: transparent; transition: .4s cubic-bezier(0, 0.8, 0, 1); position: absolute; top: 0; right: 0; z-index: 2; } input:focus { width: 300px; z-index: 1; border-bottom: 2px solid #F9F0DA; } button { background: #683B4D; border: none; height: 42px; width: 42px; position: absolute; top: 0; right: 0; cursor: pointer; } button:before { content: "\f002"; font-family: FontAwesome; font-size: 16px; color: #F9F0DA; }

8. Увеличивающееся в ширину поле поиска

* {box-sizing: border-box;} form { width: auto; float: right; margin-right: 30px; } input { width: 250px; height: 42px; padding-left: 15px; border-radius: 42px; border: 2px solid #324b4e; background: #F9F0DA; outline: none; position: relative; transition: .3s linear; } input:focus { width: 300px; } button { width: 42px; height: 42px; background: none; border: none; position: absolute; top: -2px; right: 0; } button:before{ content: "\f002"; font-family: FontAwesome; color: #324b4e; }

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

Назначение

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

Разметка HTML

Для формы используется HTML5. Код очень простой:

Сбрасываем вид для формы поиска по умолчанию в браузерах Webkit

По умолчанию в браузерах Webkit форма поиска будет иметь следующий вид:

Для того, чтобы форма поиска выглядела как обычное поле ввода текста нужно добавить следующие стили:

Input { -webkit-appearance: textfield; -webkit-box-sizing: content-box; font-family: inherit; font-size: 100%; } input::-webkit-search-decoration, input::-webkit-search-cancel-button { display: none; }

Формируем нашу форму поиска

Поле ввода будет иметь обычную ширину 55px и раскрываться для 130px в состоянии :focus . Свойство transition используется для анимации, а box-shadow используется для эффекта свечения.

Input { background: #ededed url(img/search-icon.png) no-repeat 9px center; border: solid 1px #ccc; padding: 9px 10px 9px 32px; width: 55px; /* Ширина по умолчанию */ -webkit-border-radius: 10em; -moz-border-radius: 10em; border-radius: 10em; -webkit-transition: all .5s; -moz-transition: all .5s; transition: all .5s; } input:focus { width: 130px; /* Ширина при наличии фокуса ввода */ background-color: #fff; border-color: #6dcff6; -webkit-box-shadow: 0 0 5px rgba(109,207,246,.5); -moz-box-shadow: 0 0 5px rgba(109,207,246,.5); box-shadow: 0 0 5px rgba(109,207,246,.5); /* Эффект свечения */ }

Пример В

В примере B форма поиска существенно минимизирована - выводится только иконка без заполняющего текста. Обратите внимание, что изменились свойства padding и width для поля поиска, чтобы сформировать круглую кнопку. Для того, чтобы текст был невидим используется свойство color:transparent .

#demo-b input { width: 15px; padding-left: 10px; color: transparent; cursor: pointer; } #demo-b input:hover { background-color: #fff; } #demo-b input:focus { width: 130px; padding-left: 32px; color: #000; background-color: #fff; cursor: auto; }

Совместимость с браузерами

Описанный метод работает во всех основных браузерах: Chrome, Firefox, Safari, и IE8+. В IE7 и старых браузерах функционал не действует по причине отсутствия поддержки псевдо-класса:focus и типа поля поиска.

Пособие по тому, как сделать мобильно-ориентированную и адаптивную строку поиска

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

В общем, чего мы хотим добиться от строки поиска:

  • изначально отображать только кнопку с иконкой поиска
  • при клике на иконку нужно, чтобы поисковая строка выезжала в сторону
  • компонент должен быть гибким, в том смысле, чтобы его можно было использовать в адаптивном интерфейсе
  • когда пользователь печатает что-то в строке, нужно чтобы форму можно было отправить нажатием кнопки Enter или кликом по кнопке поиска
  • если поле раскрыто, и данные в него не введены, а мы нажимаем кнопку поиска - поле ввода должно закрыться
  • также нужно, чтобы поле ввода закрывалось, если мы нажимаем куда-то вне поля поиска, независимо от того, пустое оно или нет
  • если JavaScript отключен, поле поиска должно отображаться раскрытым
  • для лучшего взаимодействия с тач-устройствами также надо добавить поддержку тач-событий

Теперь мы определились со всем, что нам нужно сделать, давайте начнем с разметки.

Разметка

В разметке используем основной контейнер, форму, текстовое поле и кнопку отправки, а также span-элемент для иконки:

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

Теперь, когда все элементы на своих местах, стилизуем их.

CSS

Исходя из наших требований, сперва убедимся, что у нас есть кнопка с видимой иконкой поиска. Все остальное должно быть спрятано. Но также подумаем на шаг вперед и представим, что случится, когда мы расширим строку поиска (с основным контейнером). Как нам это сделать? Используем свойство overflow: hidden , а изменение ширины контейнера sb-search должно проявить поле ввода.

Так что в первую очередь стилизуем контейнер sb-search. Заставим его находиться в плавающем состоянии справа, и зададим ему overflow: hidden . Его исходная ширина будет равняться 60px, но так как мы хотим анимировать до ширины 100%, это вызовет проблемы в мобильных браузерах (iOS). Они не любят переходы из пиксельной ширины в процентную. В этом случае они просто не осуществят переход. Так что вместо этого зададим минимальную ширину в 60px, а ширину в 0%.

Также добавим переход для ширины свойством -webkit-backface-visibility: hidden, что избавит от нежелательных “хвостов” на мобильных браузерах (iOS):

Sb-search { position: relative; margin-top: 10px; width: 0%; min-width: 60px; height: 60px; float: right; overflow: hidden; -webkit-transition: width 0.3s; -moz-transition: width 0.3s; transition: width 0.3s; -webkit-backface-visibility: hidden; }

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

Теперь, давайте спозиционируем поле ввода. Мы используем процентную ширину, так что когда мы раздвинем родительский элемент, поле ввода расширится вместе с ним. Выставление правильной высоты, размера шрифта и полей гарантирует, что текст будет отцентрирован (line-height не отработает в IE8 как могло бы ожидаться, так что вместо этого используем поля). Абсолютное позиционирование поля ввода не обязательно, но оно решает противную проблемку с тем, что иногда при закрытии поля поиска на короткий период времени оно отображается справа от кнопки.

Sb-search-input { position: absolute; top: 0; right: 0; border: none; outline: none; background: #fff; width: 100%; height: 60px; margin: 0; z-index: 10; padding: 20px 65px 20px 20px; font-family: inherit; font-size: 20px; color: #2c3e50; } input.sb-search-input { -webkit-appearance: none; -webkit-border-radius: 0px; }

В дополнение ко всему, мы убираем стандартные стили полей ввода браузеров для движка WebKit.

Давайте зададим цвета текста, используя собственные свойства конкретных браузеров:

Sb-search-input::-webkit-input-placeholder { color: #efb480; } .sb-search-input:-moz-placeholder { color: #efb480; } .sb-search-input::-moz-placeholder { color: #efb480; } .sb-search-input:-ms-input-placeholder { color: #efb480; }

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

Sb-icon-search, .sb-search-submit { width: 60px; height: 60px; display: block; position: absolute; right: 0; top: 0; padding: 0; margin: 0; line-height: 60px; text-align: center; cursor: pointer; }

В изначальном положении мы хотим, чтобы кликабельной была иконка поиска, а когда мы раскроем поле поиска, мы хотим чтобы кликабельной была кнопка отправки формы. Так что изначально зададим кнопке отправки формы z-index=-1, и сделаем ее прозрачной, так чтобы мы всегда видели span с иконкой поиска:

Sb-search-submit { background: #fff; /* для IE */ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; /* IE 8 */ filter: alpha(opacity=0); /* IE 5-7 */ opacity: 0; color: transparent; border: none; outline: none; z-index: -1; }

Почему бы просто не сделать её фон прозрачным? Да потому, что это не работает в IE, так как элемент не является кликабельным. Так что вместо этого мы используем сплошной фон, и выставляем элементу прозрачность в 0.

Иконка поиска изначально будет иметь высокий z-index, так как нам надо, чтобы она выводилось поверх всего. Используем псевдо-элемент :before , чтобы добавить иконку поиска:

Sb-icon-search { color: #fff; background: #e67e22; z-index: 90; font-size: 22px; font-family: "icomoon"; speak: none; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; -webkit-font-smoothing: antialiased; } .sb-icon-search:before { content: "\e000"; }

Не забудьте подключить иконочный шрифт в самом начале нашего CSS:

@font-face { font-family: "icomoon"; src:url("../fonts/icomoon/icomoon.eot"); src:url("../fonts/icomoon/icomoon.eot?#iefix") format("embedded-opentype"), url("../fonts/icomoon/icomoon.woff") format("woff"), url("../fonts/icomoon/icomoon.ttf") format("truetype"), url("../fonts/icomoon/icomoon.svg#icomoon") format("svg"); font-weight: normal; font-style: normal; }

С теми стилями, которые мы только что определили, можно просто изменить ширину контейнера sb-search на 100%, присвоив класс sb-search-open. Без JavaScript поле поиска будет открыто по умолчанию:

Sb-search.sb-search-open, .no-js .sb-search { width: 100%; }

Давайте сменим цвет иконки поиска и выставим его за кнопкой отправки формы, задав z-index меньшее значение:

Sb-search.sb-search-open .sb-icon-search, .no-js .sb-search .sb-icon-search { background: #da6d0d; color: #fff; z-index: 11; }

И, наконец, зададим кнопке отправки формы z-index более высокое значение, чтобы мы могли на него кликнуть:

Sb-search.sb-search-open .sb-search-submit, .no-js .sb-search .sb-search-submit { z-index: 90; }

Итак, все стили описаны, давайте займемся JavaScript.

JavaScript

Начнем с переключения класса sb-search-open. Будем добавлять класс тогда, когда будет производиться клик на основной контейнер (sb-search) и убирать его тогда, когда будет произведен клик по кнопке отправки формы, но только, если в поле ничего не записано. Иначе мы просто отправим форму. Чтобы не удалять класс при клике на поле ввода (так как наши триггеры заданы для всего контейнера), нужно предотвратить всплывание события click на этом элементе. Это означает, что при клике на поле ввода не будет вызвано событие click для родительских элементов.

;(function(window) { function UISearch(el, options) { this.el = el; this.inputEl = el.querySelector("form > input.sb-search-input"); this._initEvents(); } UISearch.prototype = { _initEvents: function() { var self = this, initSearchFn = function(ev) { if(!classie.has(self.el, "sb-search-open")) { // открываем ev.preventDefault(); self.open(); } else if(classie.has(self.el, "sb-search-open") && /^\s*$/.test(self.inputEl.value)) { // закрываем self.close(); } } this.el.addEventListener("click", initSearchFn); this.inputEl.addEventListener("click", function(ev) { ev.stopPropagation(); }); }, open: function() { classie.add(this.el, "sb-search-open"); }, close: function() { classie.remove(this.el, "sb-search-open"); } } // заносим в глобальное пространство имен window.UISearch = UISearch; })(window);

Далее нужно добавить события для удаления класса sb-search-open, если мы кликаем куда-то за пределами нашей строки поиска. Для того, чтобы это работало также надо позаботиться о всплывании событий при клике на основной контейнер.

;(function(window) { function UISearch(el, options) { this.el = el; this.inputEl = el.querySelector("form > input.sb-search-input"); this._initEvents(); } UISearch.prototype = { _initEvents: function() { var self = this, initSearchFn = function(ev) { ev.stopPropagation(); if(!classie.has(self.el, "sb-search-open")) { // открываем ev.preventDefault(); self.open(); } else if(classie.has(self.el, "sb-search-open") && /^\s*$/.test(self.inputEl.value)) { // закрываем self.close(); } } this.el.addEventListener("click", initSearchFn); this.inputEl.addEventListener("click", function(ev) { ev.stopPropagation(); }); }, open: function() { var self = this; classie.add(this.el, "sb-search-open"); // закрываем поле поиска, если был клик где-то вне контейнера var bodyFn = function(ev) { self.close(); this.removeEventListener("click", bodyFn); }; document.addEventListener("click", bodyFn); }, close: function() { classie.remove(this.el, "sb-search-open"); } } // заносим в глобальное пространство имен window.UISearch = UISearch; })(window);

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

Также при клике на иконку поиска, нужно сделать так, чтобы фокус перемещался на поле ввода. Так как это вызывает отрывистую отрисовку на мобильных устройствах (iOS), так как в это же время открывается и клавиатура, то нам надо как-то предотвратить открытие клавиатуры для таких случаев. Когда мы закрываем поле поиска, нужно убрать с него фокус. Это решает проблемы, когда на некоторых устройствах после закрытия поля поиска все еще отображается мигающий курсор.

;(function(window) { // http://stackoverflow.com/a/11381730/989439 function mobilecheck() { var check = false; (function(a){if(/(android|ipad|playbook|silk|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm(os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s)|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez(0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp(i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac(|\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt(|\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg(g|\/(k|l|u)|50|54|\-)|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v)|mwbp|mywa|n10|n20|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-(|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v)|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-|)|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera); return check; } // http://www.jonathantneal.com/blog/polyfills-and-prototypes/ !String.prototype.trim && (String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ""); }); function UISearch(el, options) { this.el = el; this.inputEl = el.querySelector("form > input.sb-search-input"); this._initEvents(); } UISearch.prototype = { _initEvents: function() { var self = this, initSearchFn = function(ev) { ev.stopPropagation(); // удаляем лишние пробельные символы self.inputEl.value = self.inputEl.value.trim(); if(!classie.has(self.el, "sb-search-open")) { // открываем ev.preventDefault(); self.open(); } else if(classie.has(self.el, "sb-search-open") && /^\s*$/.test(self.inputEl.value)) { // закрываем self.close(); } } this.el.addEventListener("click", initSearchFn); this.inputEl.addEventListener("click", function(ev) { ev.stopPropagation(); }); }, open: function() { var self = this; classie.add(this.el, "sb-search-open"); // переносим фокус на поле ввода if(!mobilecheck()) { this.inputEl.focus(); } // закрываем поле поиска, если был клик где-то вне контейнера var bodyFn = function(ev) { self.close(); this.removeEventListener("click", bodyFn); }; document.addEventListener("click", bodyFn); }, close: function() { this.inputEl.blur(); classie.remove(this.el, "sb-search-open"); } } // заносим в глобальное пространство имен window.UISearch = UISearch; })(window);

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

;(function(window) { // http://stackoverflow.com/a/11381730/989439 function mobilecheck() { var check = false; (function(a){if(/(android|ipad|playbook|silk|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm(os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s)|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez(0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp(i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac(|\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt(|\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg(g|\/(k|l|u)|50|54|\-)|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v)|mwbp|mywa|n10|n20|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-(|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v)|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-|)|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera); return check; } // http://www.jonathantneal.com/blog/polyfills-and-prototypes/ !String.prototype.trim && (String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ""); }); function UISearch(el, options) { this.el = el; this.inputEl = el.querySelector("form > input.sb-search-input"); this._initEvents(); } UISearch.prototype = { _initEvents: function() { var self = this, initSearchFn = function(ev) { ev.stopPropagation(); // удаляем лишние пробельные символы self.inputEl.value = self.inputEl.value.trim(); if(!classie.has(self.el, "sb-search-open")) { // открываем ev.preventDefault(); self.open(); } else if(classie.has(self.el, "sb-search-open") && /^\s*$/.test(self.inputEl.value)) { // закрываем ev.preventDefault(); self.close(); } } this.el.addEventListener("click", initSearchFn); this.el.addEventListener("touchstart", initSearchFn); this.inputEl.addEventListener("click", function(ev) { ev.stopPropagation(); }); this.inputEl.addEventListener("touchstart", function(ev) { ev.stopPropagation(); }); }, open: function() { var self = this; classie.add(this.el, "sb-search-open"); // переносим фокус на поле ввода if(!mobilecheck()) { this.inputEl.focus(); } // закрываем поле поиска, если был клик где-то вне контейнера var bodyFn = function(ev) { self.close(); this.removeEventListener("click", bodyFn); this.removeEventListener("touchstart", bodyFn); }; document.addEventListener("click", bodyFn); document.addEventListener("touchstart", bodyFn); }, close: function() { this.inputEl.blur(); classie.remove(this.el, "sb-search-open"); } } // заносим в глобальное пространство имен window.UISearch = UISearch; })(window);

И, наконец, для браузеров, которые не поддерживают addEventListener и removeEventListener , будем использовать EventListener от Jonathan Neal.

// EventListener | @jon_neal | //github.com/jonathantneal/EventListener !window.addEventListener && window.Element && (function () { function addToPrototype(name, method) { Window.prototype = HTMLDocument.prototype = Element.prototype = method; } var registry = ; addToPrototype("addEventListener", function (type, listener) { var target = this; registry.unshift({ __listener: function (event) { event.currentTarget = target; event.pageX = event.clientX + document.documentElement.scrollLeft; event.pageY = event.clientY + document.documentElement.scrollTop; event.preventDefault = function () { event.returnValue = false }; event.relatedTarget = event.fromElement || null; event.stopPropagation = function () { event.cancelBubble = true }; event.relatedTarget = event.fromElement || null; event.target = event.srcElement || target; event.timeStamp = +new Date; listener.call(target, event); }, listener: listener, target: target, type: type }); this.attachEvent("on" + type, registry.__listener); }); addToPrototype("removeEventListener", function (type, listener) { for (var index = 0, length = registry.length; index < length; ++index) { if (registry.target == this && registry.type == type && registry.listener == listener) { return this.detachEvent("on" + type, registry.splice(index, 1).__listener); } } }); addToPrototype("dispatchEvent", function (eventObject) { try { return this.fireEvent("on" + eventObject.type, eventObject); } catch (error) { for (var index = 0, length = registry.length; index < length; ++index) { if (registry.target == this && registry.type == eventObject.type) { registry.call(this, eventObject); } } } }); })();

И вот оно! Надеюсь, вам понравилось данное руководство, и вы почерпнули из него что-то полезное для себя!