Selectik — стильные селекты

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

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

Естественно, после всего этого я решил изобрести свой велосипед.

Пример разработан без дополнительных картинок с помощью CSS3. Демо-страница с песочницей здесь.

Опять велосипед?


Достаточно долго я дописывал, создавал костыли при использовании готовых плагинов. Последней каплей стал тот факт, что тестеры при написании Unit-тестов пытаются достучаться, в первую очередь, до стандартного селекта, но это не выходит, так как большинство плагинов, которые я использовал скрывают стандартный селект через «display=none».

Также я хотел иметь легкое решение, быструю генерацию (в IE при большом количестве селектов на странице), работающие точно также как и оригинальный селект.

Плагины, которые я использовал чаще всего отталкивались от событий связанных с уже созданной структурой стилизированного селекта. В случае Selectik'a, события в основном повешены именно на оригинальный селект.

Библиотекой было решено использовать jQuery, по двум причинам:
  • Сейчас большинство создаваемых сайтов используют именно эту библиотеку.
  • На нативном JavaScript'е создание заняло бы намного больше времени и количество кода зашкаливало.

И так, что же из себя представляет Selectik?


В minify-версии вес файла скрипта всего 5,2 Кб. А с дополнительным плагином (скролл колеса мыши) и CSS в демо-примере 12,8 Кб. GZIP 2,1 Кб/4,7 Кб соответственно.

Поддерживаемые браузеры: IE7+, последние версии Chrome, Safari, Firefox.

Возможности, которые на данный момент реализованы:
  • управление клавишами вверх/вниз и Enter
  • стилизированная прокрутка
  • скролл колесом мыши
  • поиск элементов по буквам
  • автоматически подстраивает ширину
  • «умное позиционирование»
  • реагирует на переход Tab'ом
Параметры, которые можно использовать:
  • назначение ширины списка (в стандартном случае высчитывается ширина оригинального списка)
  • максимальное количество видимых элементов
  • выбора типа прокрутки — стилизированный или стандартный
  • скорость анимации открытия и закрытия списка
API:
  • обновление стилизированного списка
  • открытие/закрытие списка
  • назначение нового активного элемента
  • динамическое изменение ширины
  • включение/выключение списка

В будущем

  • поддержка мобильных устройств
  • ваши пожелания в комментариях
Проект на GitHub. Демо-страница с песочницей здесь.
Буду благодарен, если ошибки/проблемы вы сможете описать в issue.

update
Как зметил Connor требуется версия jQuery 1.7+ из-за использования .on(). Вероятнее всего будет заменено на .bind().

update 2
Всем спасибо за замечания и баги. В течении недели будет сделано.
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 74
  • +3
    А я бы еще порекомендовал эту библиотеку harvesthq.github.com/chosen/, у нее уже довольно большое комьюнити и выглядит покрасивее, хотя это уже на вкус.
    • 0
      Вы хотели сказать «плагин»? Спасибо, видел его. В моем случае, как я писал, хотелось легкого (вес определяющий), простого и не нагруженого решения.
      • 0
        у chosen есть один недостаток — подогнать его под основной дизайн сайта довольно сложно. При этом схожих стилей для остальных элементов форм, выполненных в том же стиле как и селекты в нем нет.
        • 0
          Что-то я не помню сложностей при изменении дизайна. Подогнал идеально под дизайн своего сайта, времени, помнится, заняло совсем немного. Ссылку не кидаю, сочтут за рекламу :)
        • 0
          Тоже им пользуюсь.
          • 0
            За этот плагин спасибо!
          • 0
            Стрелки вверх-вниз вызывают смену выбранного и одновременно с этим открытие-закрытие окна на каждое нажатие стрелкой. Выглядит жутко.
            Opera12/lin/64
            • 0
              Да, действительно, есть проблема в Опере. Спасибо, будет сделано.
              • +2
                В Опере теперь работает. Нашлась интересная загвоздка в поведении Оперы: при нажатии клавиши вверх/вниз на оригинальном селекте отрабатывается событие «клик» мыши.
                • +4
                  Опера полна подобных «загвоздок».
                  • 0
                    Я старался сделать под все браузеры, но 99% проектов с которыми я работаю не требуют поддержки Оперы.
                    • +2
                      Как много интересного вы пропустили в работе…
                      • 0
                        Возможно. А может у меня появилось больше времени на работу с Javascript, а не разработки костылей.
              • 0
                могу еще порекомендовать данный вариант linkselect, имеет хороший API
                • 0
                  Интересно, но весьма своеобразное решение: оригинальный селект они заменяют на инпут. В моих целях не подходит.
                  • 0
                    «заменяют на инпут» — в плане внутреннего устройства или внешнего отображения?
                    там есть у них разные варианты дизайна, включая вид обычного селекта
                    • +1
                      В плане внутреннего устройства.
                • 0
                  Вот тоже, кстати, симпатичный.
                  • +1
                    Симпатичный. Подскажите, где вы видите его использование, в каком случае?
                    • 0
                      Например, я бы поставил такой на apple.com, он бы там смотрелся отлично :)
                      • +2
                        В визуальном смысле — да. Практичности не вижу… Поведение селекта достаточно сильно отличается от стандартного. Большинство пользователей могут не понять.
                  • 0
                    Вы кстати написали бы, что требуется jQuery 1.7+, а то ведь не все веб-мастера обновляют библиотеку(.on() только с 1.7 появился).
                  • 0
                    Если добавить пункт с длинным текстом — начинаются проблемы :)

                    Эту проблему пока ни один заменитель селектов не решает, к сожалению.
                    • 0
                      Как отписался внизу Rozzy: можно изменить CSS под ваши требования. В стандартной версии решил не скрывать текст — при разработке будет не удобно.
                      • 0
                        Всё верно, но элемента меняется ширина(«width») с помощью инлайновых стилей.

                        Их можно перебить, но все же.
                        • 0
                          Возможно вас не понял, но ширину вы можете назначить при вызове плагина.
                    • 0
                      В таких случаях нужно ограничить ширину (допустим, max-width) и добавить свойство text-overflow.

                      white-space: nowrap;
                      max-width: 200px;
                      text-overflow: ellipsis;
                      -o-text-overflow: ellipsis;
                      overflow: hidden;
                      • 0
                        Баг двойных стрелок в линуксовом Chrome 17.0.963.26 dev.
                        Эта чёрная стрелка — от дефолтного выпадающего списка, если его спрятать (display: none), то всё нормально.
                        • 0
                          Такая же версия Win — проблемы нет. На том, что селект виден построен плагин. Так как dev версия — думаю, что баг в Chrome. Но все равно проверю на Ubuntu.
                        • +1
                          Не очень удобно, что при повторном нажатии на селект, он не закрывается, как стандартный.

                          Тоже, кстати, писал обзор плагинов и сам остался не очень доволен тогдашним положением дел, всё косо-криво. Скоро попробую ваш вариант, надеюсь, что вы сделали мой идеал =)
                          • +1
                            Занес в изменения повторное нажатие. Релизую сегодня-завтра.

                            Как раз на ваш обзор и ориентировался при написании статьи. )
                            • 0
                              Забрал с github последнюю версию, все-равно при повторно клике заново моргает и появляется список, не сворачивается
                          • +1
                            А почему нет поддержки такой удобной вещи как OPTGROUP? На своём веку помню лишь пару плагинов хоть с кривой и упрощенной, но поддержкой групп.
                            • 0
                              На данный момент занес в TODO возможность отключить стилизицию к селектам с OPTGROUP, и атрибутом multiple select. Повторюсь: идея была только для стандартных селектов без этих возможностей. Редко встречаются. Если надо пддержка такой функциональности — используйте указанный в первом комментарии Chosen.
                            • +1
                              Хочется поведения выпадающих списков как у нативных. Кликнули на выпадающий список — он развернулся, кликнули еще раз — у вас он повторно развернулся, хотя в оригинале должен свернуться.
                              • 0
                                Как было указано выше будет сделано.
                                • 0
                                  Прошу прощения, сразу не заметил
                              • 0
                                Тестовый пример не работает в IE (причём даже в девятом). Наверное что-то поломалось =)

                                image
                                • 0
                                  Вот ссылка на полноразмерный скрин.
                                  • 0
                                    В IE8 работает, но не видно галочку справа.
                                    • 0
                                      Объект селектора :after в CSS не отображаются. Исправлю для IE.
                                • 0
                                  Спасибо. Проверю.
                                  • 0
                                    В мобильном Safari отображается выпадающий список и одновременно с ним появляется стандартный селектор в виде барабана. Выбор пункта на барабане и подтверждение кнопкой Done выделяет пункт в списке, который продолжает «свисать». Приходится повторно тапать по пункту, после чего список наконец сворачивается.
                                    • 0
                                      Для мобильных устройств, на данный момент, вообще не планировалось использовать — есть стандартное нормальное поведение.
                                      • 0
                                        Нужно встроить проверку на мобильные браузеры, чтобы селект для них не применялся, т.к. текущее поведение не корректное.
                                        • 0
                                          Да, добавлю в TODO — спасибо.
                                    • 0
                                      Ваш плагин я бы не назвал бы велосипедом, действительно предусмотрено большинство событий как у стандартного элемента select. Я бы посоветовал сделать срытие списка не по событию на документ, а при потере фокуса, как это реализовано в виджите popup jQueryUI, чтобы избежать конфликтов с другими плагинами.
                                      • 0
                                        Тут есть несколько подводных камней, например, при клике по скролу или фону скрола фокус будет теряться. Надо ставить дополнительные проверки. Постараюсь как сделать лучше.
                                        • 0
                                          В jQuery UI это решается установкой таймера(это я насчет фона), а вот насчет скрола, да здесь стоит подумать.
                                      • +1
                                        Ребята, как мне необходима была сегодня эта статья! Спасибо! :)
                                        • 0
                                          Пользуйтесь на здоровье, только прошу отписать, если будут баги/замечания, чтобы улучшить плагин.
                                        • 0
                                          Не нашёл в демке — есть ли поддержка кнопки «reset»?
                                          Пока ни у одного самописного селекта не видел сброса в начальное состояние при нажатии reset в форме, каждый раз приходится писать костыли вручную, поскольку спрятанный оригинальный селект сбрасывается, а на подменяющем его скриптовом селекте это никак не отражается.
                                          • +1
                                            Нет, спасибо за замечание — сделаю.
                                          • 0
                                            О ужас, не хотелось бы чтоб это было повсеместно.
                                            • 0
                                              Что именно?
                                              • 0
                                                такие селекты и прочее, очень в редких случаях это можно встроить в дизайн, чаще это излишнее…
                                                • 0
                                                  А можно поинтересоваться, по какой причине их сложно встроить в дизайн?
                                                  • 0
                                                    Согласен с частью: да, мне как верстальщику легче оригинальные элементы, так привычнее и проще, но дизайн элементов все чаще и чаще изменяется (например элементы форм в наших мобильных устройствах). И не скажу, что это излишне…
                                              • +1
                                                Не стоит использовать классы вроде «done, open». Очень велика вероятность того, что аналогичные классы встретятся в проекте, где ваш селект будет использоваться (custom-select тоже кстати весьма популярный класс). Сделайте возможность задания своего класса, а вспомогательные классы пусть будут генерироваться с префиксом (.your-class-name-select-open, .your-class-name-select-done).
                                                • +1
                                                  Сделаю, спасибо за замечание.
                                                • +2
                                                  Вообще селект понравился. Аккуратная верстка, симпатичен внешне. Буду контрибьютить.
                                                  • +2
                                                    Правда есть вопросы по js:

                                                    1. Зачем вы конструктор вашего плагина делаете свойством объекта jQuery?

                                                    $.selectik = function(element, options) {}
                                                    /* source code */
                                                    $.fn.selectik = function(options) {
                                                        return this.each(function() {
                                                            if (undefined == $(this).data('selectik')) {
                                                                // create a new instance of the plugin
                                                                var selectik = new $.selectik(this, options);
                                                                $(this).data('selectik', selectik);
                                                            }
                                                        });
                                                    }
                                                    


                                                    2. Почему не храните методы в прототипе?

                                                    // public method: disable list
                                                    selectik.disableCS = function(){}
                                                    // public method: enable list
                                                    selectik.enableCS = function(){}
                                                    // public method: width of select
                                                    selectik.setWidthCS = function(width){}
                                                    
                                                    • +1
                                                      За основу был взять шаблон для плагина Стефана Габоса. Мне понравилась идеи хранения методов и определение свойств именно в таком виде, поэтому и использовал.
                                                      Возможно в будущем будет переработана архитектура после всех доработок. Возьму на заметку!
                                                      • +2
                                                        Ну если по поводу первого пункта еще можно поспорить: мало ли кто-то захочет запускать плагин как

                                                        $.selectik(element, { option1: 'option' });
                                                        

                                                        Но методы нужно конечно в прототип пихать. Они же общие для всех инстансов, зачем их дублировать для каждого селекта.
                                                        Когда будете пересматривать архитектуру, загляните сюда (если конечно еще не заглядывали).
                                                        • +1
                                                          О! Спасибо за ссылку, обязательно изучу и постараюсь взять лучшее.
                                                    • –1
                                                      Мне не нравится такие несемантичные списки. DIV-ами и LI-шками рисовать вручную контрол? Вы, что застряли во времена DOS, когда каждая программа рисовала контролы как могла? Это шаг в прошлое. Я против распространения таких методов.
                                                      • 0
                                                        1. Если дизайнер видет это не стандартно и пользователю будет удобно — то почему нет? Надо учитывать и тот фактор, что они будут выглядеть во всех браузерах одинаково.
                                                        2. Чем несемантичные?
                                                        • –1
                                                          1. Пикассо тоже всякую хрень рисовал, и у него даже есть поклонники, но это не значит, что это хорошие картины. То, что видит дизайнер никого не волнует. Пользователю удобно было бы, и если бы производители браузеров и стандартов реализовали эти фичи с стандартном элементе управления. А делать костыль из-за чьей-то лени — это не престижно и унизительно. Логичнее для мировой справедливости заставить лентяев из W3C быстрее работать. Одинаковое отображение во всех браузерах опять-таки зависит от того, как мировое население сумеет заставить программистов браузеров хорошо работать, а не пить кофе с печеньками.
                                                          2. Несемантичные тем, что парсеры таких списков писать неудобно — везде свои. Да и представьте, если бы программы для Windows сами рисовали на окне элементы управления. Что было бы?! Да даже GetWindowText не сработал бы! У каждой программы был бы свой GetWindowText.

                                                          Поставьте, пожалуйста, мне плюсов в карму за выражение моего собственного мнения отличного от мнения большинства.
                                                      • +2
                                                        '+valueOption+'

                                                        Это жесть. Почему вместо текста option используется его value? Получается, я не могу использовать список вида:

                                                        По-умолчанию
                                                        Красный
                                                        Зеленый
                                                        Синий

                                                        • +2
                                                          Блин, хабратеги, первый раз использую… =(

                                                          В общем суть, что натравив на селект, где value отличается от text опшена, мы получаем, что в тексте вашего селекта отображается именно value…
                                                          • 0
                                                            Спасибо, суть понята. Уже написали на GitHub. Все фиксы вместе соберу и обновлю в ближайшие дни.
                                                        • 0
                                                          FireFox 12.0, селект разворачивается вверх.
                                                          • 0
                                                            Подскажите пожалуйста, как обрабатывать события вроде onchange?
                                                            Например, для цепочки селектов, или отправки формы сразу по смене, и т.п.
                                                            В демо и API такого примера не нашёл

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