# cuSel — нестандартные select на jQuery

Подготовил: Евгений Рыжков Дата публикации: 24.06.2010
Последнее обновление: 28.06.2011

### Задача

Изменить дизайн select. Например на такой:

### Требования

- легкость интеграции
- кроссбраузерность
- быстрая скорость работы
- максимальная приближенность к работе обычного select:
  - на сервер передается значение (value выбранного option)
  - по клику на option выпавший список скрывается
  - по клику вне select выпавший список скрывается
  - в выпадающем списке показ полностью длинных значений option
  - учет атрибута disabled
  - учет атрибута selected
  - если явно не указан selected, select принимает значение первого в списке option
  - учет события onchange
  - скроллинг выпадающего списка прокручивается колесом мыши
  - возможность получения фокуса (update 31.07.10)
  - участие в tab обходе (update 31.07.10)
  - смена значения select стрелками вверх/вниз (update 31.07.10) — после выбора нужного значения требуется нажатие enter
  - смена значения select по нажатию клавиш букв (update 31.07.10)
  - подсветка select при наведении и получении фокуса (update 31.07.10)
  - закрытие списка по Esc (update 3.08.10)
- при отключенном javascript остаются обычные select
- удобное динамическое обновление оптионов
- простота динамического добавления select
- дополнительные приятные возможности:
  - подсветка в выпадающем списке выбранного значения
  - подсветка в выпадающем списке значения при наведении
  - возможность ручного управления видом скроллинга выпадающего списка
  - возможность оформления option с помощью CSS
  - возможность вставки тегов в option
  - плавное обрезание невмещающегося текста

Демо пример возможностей cuSel (или можно забрать архивом). Проверено в:

- IE 6-8
- Firefox 4
- Opera 9.5-11
- Safari 5
- Chrome 4

## Что качать

- библиотеку jquery версии не ниже 1.6
- cusel-min-2.5.js (11.1Kb)
- cusel.css
- спрайт для образца

### Заметка

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

При таком эффекте для IE6 подключаем DD_belatedPNG.

### Если охота посмотреть код

- библиотеки jScrollPane.js (оригинал был изменен) и jquery.mousewheel.js для реализации прокрутки в выпадающем списке
- cusel.js

## Быстрый старт

Подключаем необходимые стили и библиотеки:

HTML
view source
print?

`01` | `<``link` `rel``=``"stylesheet"` `type``=``"text/css"` `href``=``"path-to/cusel.css"` `/>`

`02` | `<``script` `type``=``"text/javascript"` `src``=``"path-to/jquery-1.6.1.js"``></``script``>`

`03` | `<``script` `type``=``"text/javascript"` `src``=``"path-to/cusel-min.js"``></``script``>`

`04` | `<!-- если требуется поддержка ie6, учим его понимать альфапрозрачность для плавного обрезания текста -->`

`05` | `<!--[if IE 6]>`

`06` | `<script type="text/javascript" src="path-to/DD_belatedPNG.js"></script>`

`07` | `<script type="text/javascript">`

`08` | `DD_belatedPNG.fix(".cuselFrameRight"); <!-- именно этот элемент имеет полупрозрачность -->`

`09` | `jQuery(document).ready(function(){` `<!--делаем эмуляцию min-width: 100% для выпадающего списка для IE6 (спасибо Константину Ершову) -->`

`10` | `jQuery(".cusel").each(`

`11` | `function(){`

`12` | `` `var w = parseInt(jQuery(this).width()),`

`13` | `` `scrollPanel = jQuery(this).find(".cusel-scroll-pane");`

`14` | `` `if(w>=scrollPanel.width())`

`15` | `` `{`

`16` | `` `jQuery(this).find(".jScrollPaneContainer").width(w);`

`17` | `` `scrollPanel.width(w);`

`18` | `` `}`

`19` | `});`

`20` | `});`

`21` | `</``script``>`

`22` | `<![endif]-->`

Инициализируем cusel, указывая, где и как стилизовать select:

Javascript
view source
print?

`1` | `jQuery(document).ready(function(){`

`2` | `var params = {`

`3` | `` `changedEl:` `".lineForm select"``,`

`4` | `` `visRows:` `5``,`

`5` | `` `scrollArrows: true`

`6` | `` `}`

`7` | `` `cuSel(params);`

`8` | `});`

А теперь подробней.

### Как это работает

При загрузке страницы, если у пользователя включен javascript:

1. находятся все указанные селекты на странице
2. заменяется каждый select
   HTML
   view source
   print?

   `1` | `<``select` `id``=``"idSelect"` `name``=``"nameSelect"``>`

   `2` | `<``option` `value``=``"значение option 1"``>текст option 1</``option``>`

   `3` | `...`

   `4` | `<``option` `value``=``"значение option N"``>текст option N</``option``>`

   `5` | `</``select``>`

   на конструкцию вида:
   HTML
   view source
   print?

   `01` | `<``div` `class``=``"cusel"` `id``=``"cuselFrame-idSelect"``>`

   `02` | `` `<``div` `class``=``"cuselFrameRight"``></``div``>`

   `03` | `` `<``div` `class``=``"cuselText"``>текст option 1</``div``>`

   `04` | `` `<``div` `class``=``"cusel-scroll-wrap"``>`

   `05` | `` `<``div` `class``=``"cusel-scroll-pane"` `id``=``"cusel-scroll-idSelect"``>`

   `06` | `` `<``span` `class``=``"cuselActive"` `value``=``"значение option 1"``>текст option 1</``span``>`

   `07` | `` `...`

   `08` | `` `<``span` `value``=``"значение option N"``>текст option N</``span``>`

   `09` | `` `</``div``>`

   `10` | `` `</``div``>`

   `11` | `` `<``input` `id``=``"idSelect"` `name``=``"nameSelect"` `value``=``"значение option 1"` `type``=``"hidden"``/>`

   `12` | `</``div``>`

3. обычные select удаляются

### Заметка

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

## Инициализация cuSel

### Функции

cuSel | производит замену обычных select на стилизованные. Меняет только те, которые указаны в параметре changedEl.
cuSelRefresh | производит обновление селекта. Необходимо при изменении количества option в select и при показе скрытого select. Обновляет селекты, указанные в параметре refreshEl.

### Параметры

changedEl | указываем селекторы (за основу взяты базовые селекторы CSS1) , к которым будет применен cuSel. Можно указать элемент (тег), класс, id. Обязательный параметр. Используется только в функции cuSel.
visRows | количество видимых строк выпадающего списка. Если в списке элементов будет больше заданного числа, у списка появится вертикальная прокрутка. Если число не задано, все значения списка будут видимы.
scrollArrows | отражать или нет стрелочки в блоке с прокруткой. Возможные значения: true/false (по умолчанию false)
refreshEl | id селектов через запятую, которые требуется обновить. Параметр обязателен. Используется только в функции cuSelRefresh.

## Примеры

Меняем все селекты на странице, без ограничения по высоте для выпадающих списков:

Javascript
view source
print?

`1` | `var params = {`

`2` | `` `changedEl:` `"select"`

`3` | `` `}`

`4` | `cuSel(params);`

Меняем один конкретный селект по id, число видимых элементов выпадающего списка 7:

Javascript
view source
print?

`1` | `var params = {`

`2` | `` `changedEl:` `"#city"``,`

`3` | `` `visRows:` `7`

`4` | `` `}`

`5` | `` `cuSel(params);`

Цепляем onchange списку. Сusel-селект имеет структуру, построенную на div и span. Это нужно учитывать при динамическом изменении содержимого списков:

HTML
view source
print?

`1` | `<``select` `id``=``"city"` `name``=``"city"` `onChange``=``"alert('произошел onchange')"``>`

`2` | `<``option` `value``=``"1"``>Киев</``option``>`

`3` | `<``option` `value``=``"2"``>Львов</``option``>`

`4` | `<``option` `value``=``"3"``>Дон</``option``>`

`5` | `<``option` `value``=``"4"``>Ялта</``option``>`

`6` | `</``select``>`

Javascript
view source
print?

`1` | `var params = {`

`2` | `` `changedEl:` `"#city"`

`3` | `` `}`

`4` | `` `cuSel(params);`

Если при загрузке страницы select был скрыт, то при его показе ему нужно обязательно указывать width и провести обновление:

Javascript
view source
print?

`01` | `jQuery(``"#showSel"``).click(`

`02` | `function()`

`03` | `{`

`04` | `` `jQuery(``"#hidden-select"``)`

`05` | `` `.css(``"display"``,``"block"``)`

`06` | `` `.css(``"width"``,``"100px"``);` `/* показанному селект указываем width */`

`07` | `params = {`

`08` | `` `refreshEl:` `"#hidden-select"``,`

`09` | `` `visRows:` `4`

`10` | `` `}`

`11` | `` `cuSelRefresh(params);`

`12` | `});`

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

HTML
view source
print?

`01` | `<``div` `id``=``"hidden-block"` `style``=``"display: none"``>`

`02` | `` `<``select` `id``=``"city2"` `name``=``"city2"` `class``=``"wid100"``>`

`03` | `` `<``option` `value``=``"1"``>Киев</``option``>`

`04` | `` `<``option` `value``=``"2"``>Львов</``option``>`

`05` | `` `<``option` `value``=``"3"``>Донецк</``option``>`

`06` | `` `<``option` `value``=``"4"``>Ялта</``option``>`

`07` | `` `</``select``>`

`08` | `` `<``select` `id``=``"city3"` `name``=``"city3"` `class``=``"wid100"``>`

`09` | `` `<``option` `value``=``"1"``>Киев</``option``>`

`10` | `` `<``option` `value``=``"2"``>Львов</``option``>`

`11` | `` `<``option` `value``=``"3"``>Донецк</``option``>`

`12` | `` `<``option` `value``=``"4"``>Ялта</``option``>`

`13` | `</``select``>`

CSS
view source
print?

`1` | `.wid` `100` `{`

`2` | `width``:` `100px` `!important``;` `/* !important обязателен */`

`3` | `}`

Javascript
view source
print?

`1` | `jQuery(``"#hidden-block"``).css(``"display"``,``"block"``);`

`2` | `` `params = {`

`3` | `` `refreshEl:` `"#city2, #city3"``,` `/* перечисляем через запятую id селектов, которые нужно обновить */`

`4` | `` `visRows:` `4`

`5` | `` `}`

`6` | `` `cuSelRefresh(params);`

Динамическое добавление select:

Javascript
view source
print?

`01` | `jQuery(``"#addSelect"``).click(`

`02` | `function()`

`03` | `{`

`04` | `` `var addedSelect =` `'<select id="add-select" name="add-select">'``+`

`05` | `` `'<option value="1">доллар США</option>'``+`

`06` | `` `'<option value="2">доллар канадский</option>'``+`

`07` | `` `'<option value="3">доллар новозеландский</option>'``+`

`08` | `` `'</select>'``;`

`09` | `` `jQuery(this).replaceWith(addedSelect);`

`10` | ``

`11` | `` `var params = {`

`12` | `` `changedEl:` `"#add-select"``,`

`13` | `` `visRows:` `4`

`14` | `` `}`

`15` | `` `cuSel(params);`

`16` | ``

`17` | `});`

Динамическое добавление опционов:

Javascript
view source
print?

`01` | `jQuery(``"#addAnimals"``).click(`

`02` | `function()`

`03` | `{`

`04` | `` `/* при добавлении следует учитывать, что option были заменены на span */`

`05` | `` `var newAnimals =` `'<span val="4">Слон</span><span val="5">Жираф африканский</span>'``;`

`06` | ``

`07` | `` `/* id контенера, где содержаться "option" получаем соединяя префикс cusel-scroll- и id select */`

`08` | `` `jQuery(``"#cusel-scroll-animals"``).append(newAnimals);`

`09` | ``

`10` | ``

`11` | ``

`12` | `` `var params = {`

`13` | `` `refreshEl:` `"#animals"``,`

`14` | `` `visRows:` `4`

`15` | `` `}`

`16` | `` `cuSelRefresh(params);`

`17` | ``

`18` | `});`

Дополнительные теги внутри option реализуются через дополнительный атрибут addTags. Если он присутствует, его содержимое добавится в соответствующий "новый" option:

HTML
view source
print?

`1` | `<``select` `id``=``"animals"` `name``=``"animals"``>`

`2` | `` `<``option` `value``=``"1"` `addTags="<div` `class``=``'kv'``></``div``>">Медведь</``option``>`

`3` | `` `<``option` `value``=``"2"` `addTags="<input` `type``=``'checkbox'` `/>">Волк</``option``>`

`4` | `` `<``option` `value``=``"3"``>Заяц</``option``>`

`5` | `` `<``option` `value``=``"4"``>Ежик</``option``>`

`6` | `</``select``>`

## Часто задаваемые вопросы

### Как на одной странице сделать два селекта разного вида

Нужно привязывать оформление селекта относительно своего родителя:

CSS
view source
print?

`1` | `.parent` `1` `.cusel {`

`2` | `/* описываем оформление селекта первого вида */`

`3` | `}`

`4` | `.parent` `2` `.cusel {`

`5` | `/* описываем оформление селекта второго вида */`

`6` | `}`

Можно подключить разные фоны, использовать разные цветовые схемы, шрифты и т.п.

Или же можно использовать дополнительный класс:

HTML
view source
print?

`1` | `<``select` `id``=``"select1"` `name``=``"select1"``>`

`2` | `...`

`3` | `<``select` `id``=``"select2"` `name``=``"select2"` `class``=``"cusel2"``>`

`4` | `...`

CSS
view source
print?

`1` | `.cusel {`

`2` | `/* описываем оформление селекта первого вида */`

`3` | `}`

`4` | `.cusel` `2` `{`

`5` | `/* описываем оформление селекта второго вида */`

`6` | `}`

### Как убрать выделение выбранного пункта в выпадающем списке

Из CSS удаляем класс .cuselActive.

### Как задать ширину стилизированного select

В CSS указать явно ширину классу .cusel или добавить класс, с явно заданной шириной заменяемому select.

### В прозрачной части cuSel виден фон, который находится под ним

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

### Как убрать подсветку select при наведении и получении фокуса (update 31.07.10)

Достаточно убрать из стилей:

CSS
view source
print?

`01` | `/*`

`02` | `` `styles for focus and hover`

`03` | `*/`

`04` | `.cusel:hover,`

`05` | `.cusel:hover .cuselFrameRight,`

`06` | `.cusel:focus,`

`07` | `.cusel:focus .cuselFrameRight,`

`08` | `.cuselFocus,`

`09` | `.cuselFocus .cuselFrameRight {`

`10` | `` `background-image``:` `url``(path-to/selects-focus.png);`

`11` | `}`

### Как динамически управлять disabled

Пример приведен в перечне доработок версии 2.3.

## Улучшения по сравнению с предыдущей версией:

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

## Предыдущая версия

- selects.png (370b) — составная картинка для всех частей селекта (удобно использовать в качестве примера)
- selects.css (3.5 Kb) — таблица стилей для нестандартных select
- selectsComments.css (6.5 Kb) — таблица стилей с комментариями
- jquery.js (55.9 Kb) — библиотека jQuery версии 1.3.2
- jsScroll.js (8.13 Kb) — библиотека для реализации нестандартно оформленного скроллинга
- jquery.selects.js (12 Kb) — библиотека замены select на нестандартные
- jquery.selects_pack.js (3 Kb) — сжатый скрипт

## Баги/недостатки cuSel

- У option должен обязательно быть атрибут value, хотя бы пустой — это исправлять пока не вижу смысла, потому что нет понту от селекта, который не передает значения. А для исключений можно дописать value="". устранено
- список выпадает всегда вниз
- в IE6 есть нет реакции на :hover
- если по пунктам выпавшего списка пробовать перемещаться и мышью и клавиатурой, могут проскакивать некоторые глюки
- нет поддержки <optgroup>, более того, скорей всего селект, содержащий optgroup не будет функционировать.

## Пожелания / предложения

- by f0rmateg: раскрытие списка по нажатию на пробел, по аналогии как реализовано в Opera для обычных select
- by Олег Панов: предусмотреть реализацию для списков вида <select multiple size="1">
- by Николай: предусмотреть возможность динамически дизэйблить и энэйблить селекты. реализовано

## Апдейты: что было исправлено/добавлено

- Версия 2.5 (31.10.2011)
- Версия 2.4.1 (15.08.2011)
- Версия 2.4 (20.07.2011)
- версия 2.3.5 (28.06.2011)
- версия 2.3.4 (03.06.2011) — фиксы багов
- версия 2.3.2 (26.05.2011)
- версия 2.3.1 (13.10.2010)
- версия 2.3 (27.09.2010)
- версия 2.2 (31.07.2010)

Теги: стилизованные выпадающие списки, плагины, верстка форм, jquery
twitter добавить в memory.ru забобрить добавить в vkontakte.ru добавить на facebook добавить в я.ru добавить в закладки google добавить в livejournal добавить в live internet добавить в мой мир
Нравится
Tweet
Показать комментарии

- Главная
- Собираем
  - HTML и CSS приемы
  - Веб без flash
  - Будни front end разработчика
  - Сервисы
  - Javascript: решения и плагины
- Следим
  - Веб статистика
  - Куда веб катится
  - Куда Xiper катится
- Без цензуры
- Учимся
  - Photoshop для кодера
  - Уроки CSS
  - Уроки HTML
  - Уроки Javascript
  - Уроки jQuery
  - Тегофеншуй
  - Тоже нужно знать
  - Уроки SVG
  - Бонус книги
- Справочники
  - HTML справочник
  - CSS справочник
  - Справочник Canvas
  - Cловарь терминов

twitter RSS e-mail