...

понедельник, 19 января 2015 г.

Полная кастомизация 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: 500px; /** Ограничения на высоту списка выборов **/

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, но подход явно имеет право на жизнь.


Recommended article: Chomsky: We Are All – Fill in the Blank.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий