Полная кастомизация select без использования JS

imageСколько я не мучил поисковик, а решения этого вопроса так и не нашлось. Конечно, всегда можно использовать JS и это нормально, но иногда заказчик душа просит изысков.В заголовке я несколько приврал: всем известно, что select полностью кастомизировать нельзя, поэтому мы будем имитировать select. Сделаем мы это с помощью нескольких radio, нескольких label, одного checkbox и одного div. Не так уж и много, правда? Структура

Корневая label будет всегда видимой частью нашего альтернативного select. При клике на нее будет переключаться checkbox, который и отвечает за состояния открыт/закрыт у этой конструкции. Placeholder и традиционная стрелочка будут реализованы через псевдоэлементы : before и : after у корневой label. Все остальное, кроме wrapper (тот самый единственный div), по умолчанию скрыто. Почему мы не скрываем wrapper? Потому что в нем находится выбранный элемент (если такой есть), а он должен быть виден всегда.Основная часть label.selectGeneral { display: block; position: relative; }

/** Это обещанный placeholder **/ label.selectGeneral: before { content: attr (placeholder); /** Взять текст из атрибута placeholder **/ display: inline-block; position: absolute; top: 0; left: 0; z-index: -1;

max-width: 100%;

text-align: left; white-space: nowrap; /** Не переносить слова **/

color: #adadad;

overflow-x: hidden; /** Скрыть лишнее **/ }

/** А это стрелочка **/ label.selectGeneral: after { content:»<>»; display: inline-block; position: absolute; top: 0; right: 0;

text-align: center;

background-color: #ffffff;

transform: rotate (90deg); }

label.selectGeneral input, label.selectGeneral label { display: none; }

label.selectGeneral div { min-width: 100%; max-height: 500 px; /** Ограничения на высоту списка выборов **/

overflow-x: hidden; } Осталось добавить немного магии — реализовать поведение всего этого добра. Магия будет основана на соседних селекторах и : checked у radio/checkbox. Выбранный элемент виден всегда и при закрытом состоянии select перекрывает собой placeholder. При открытии select, показываются все остальные элементы для выбора, а wrapper, в который они вложены, немного съезжает вниз, что-бы было видно placeholder и пользователь не забыл, что же он, собственно, выбирает.Поведение /** Если наш альтернативный select открыт, то wrapper **/ label.selectGeneral input[type=«checkbox»]: checked ~ div { position: absolute; /** приобретает абсолютную позицию **/ top: <высота label.selectGeneral>; /** и смешается немного вниз, открывая placeholder **/

overflow-y: auto; }

/** Все label внутри wrapper’а при открытом select **/ label.selectGeneral input[type=«checkbox»]: checked ~ div > label, /** И выбранный вариант **/ label.selectGeneral input[type=«radio»]: checked + label { display: block; /** должны быть видимыми **/ }

/** Подсветим выбранный вариант **/ label.selectGeneral input[type=«checkbox»]: checked ~ div > input[type=«radio»]: checked + label, /** и элемент на который наведена мыль при открытом selec **/ label.selectGeneral input[type=«checkbox»]: checked ~ div > label: hover { background-color: #ffa834; }

/** При закрытом select, нужно делегировать событие клика мышью с выбранного элемента родительскому label **/ label.selectGeneral input[type=«checkbox»]: not (: checked) ~ div > input[type=«radio»]: checked + label { position: relative; z-index: -1; } В конце применен трюк с z-index, который позволяет расположить дочерний элемент ниже (глубже по z-оси) родительского. Этот замечательный факт позволяет делегировать реакцию на клик по выбранному элементу нашему select’у, что бы он раскрылся.Рабочий пример можно лицезреть тут.

Из плюсов подхода можно отметить:

Кроссбраузерность — это работает везде, где работают label Относительная легкость — код не перенасыщен лишними элементами Возможность полной кастомизацией — стилизуется каждая мелочь Гибкость — не придется дописывать новых стилей при добавлении пунктов выбора Конечно же, есть и минусы, куда же без них: Отсутствие деградации — если не поддерживается, то стандартный select не спасет ситуацию Легкость легкостью, а дополнительный код все таки будет Невалидный код — div внутри label и атрибут placeholder у нее же, это не по стандарту Это не совсем минус, но эта штука не захлопывается сама после выбора Не думаю, что кто-то станет использовать это в production, но подход явно имеет право на жизнь.

© Habrahabr.ru