Как-то вечером я убивал время, читая статьи в интернете, и наткнулся на вот этот хабропост пользователя Cyapa, где расписано, как кастомизировать select на чистом css. В процессе просмотра данного решения нашел несколько весьма неудобных моментов, которые постарался исправить в своем решении этой задачи. Итак, приступим.
Пока смотрел код того поста, заметил, что автор сделал селект, который невозможно закрыть при клике вне его, а также невозможность открыть селект при клике на название элемента, если оно уже выбрано.
В своем варианте кастомизации я, так же как и предыдущий автор, использовал label, input[type=«radio»] и мощь css-селекторов. Так как сам селект средствами css полностью кастомизировать нереально, я имитировал поведение селекта.
Для начала, я накидал вот такую разметку:
При просмотре данного кода у вас мог возникнуть вопрос: «Почему у всех инпутов одинаковое имя?». Отвечу сразу: это сделано для того, чтобы наш селект адекватно вел себя(открывался и закрывался тогда, когда нужно). Но обо всем по порядку. Давайте перейдем к самой интересной, на мой взгляд, части — css.
Вот она — самая интересная часть, в которой надо осмыслить как смена выбора инпута (все инпуты с типом радио имеют одинаковое имя => мы можем выбрать только один из них) влияет на наш селект. Еще одной особенностью этого варианта является возможность отключить селект, используя атрибут disabled на #select.
Готовый пример вы можете найти здесь.
Вот, собственно, и все. Парочка минусов предыдущего автора пофикшены, так что это решение, полагаю, на данный момент можно считать идеальным css-вариантом селекта. Надеюсь, мое решение кому-нибудь пригодится.
Пока смотрел код того поста, заметил, что автор сделал селект, который невозможно закрыть при клике вне его, а также невозможность открыть селект при клике на название элемента, если оно уже выбрано.
В своем варианте кастомизации я, так же как и предыдущий автор, использовал label, input[type=«radio»] и мощь css-селекторов. Так как сам селект средствами css полностью кастомизировать нереально, я имитировал поведение селекта.
Для начала, я накидал вот такую разметку:
Показать html код
<!-- Лейбел, при клике на который открывается селект --> <label for="select" class="select"> <!-- Этот инпут отвечает за закрытие селекта при клике за его пределами. Также этот инпут является стандартным значением нашего селекта --> <input type="radio" name="list" value="not_changed" id="bg" checked /> <!-- Этот инпут является переключателем селекта в состояние "открыт" --> <input type="radio" name="list" value="not_changed" id="select"> <!-- Этот лейбел используется для создания подложки, клик по которой приводит к закрытию селекта --> <label class="bg" for="bg"></label> <!-- Этот див - список параметров селекта, где #text - то, что выводится, когда ничего не выбрано --> <div class="items"> <!-- Инпут, при клике на который происходит выбор параметра и сворачивание селекта --> <input type="radio" name="list" value="first_value" id="list[0]"> <!-- Название параметра --> <label for="list[0]">First option</label> <!-- Инпут, при клике на который происходит выбор параметра и сворачивание селекта[1] --> <input type="radio" name="list" value="second_value" id="list[1]"> <!-- Инпут, при клике на который происходит выбор параметра и сворачивание селекта[1] --> <label for="list[1]">Second loooooong option</label> <!-- Текст селекта по умолчанию. Выводится тогда, когда ничего не выбрано --> <span id="text">Select something...</span> </div> </label>
При просмотре данного кода у вас мог возникнуть вопрос: «Почему у всех инпутов одинаковое имя?». Отвечу сразу: это сделано для того, чтобы наш селект адекватно вел себя(открывался и закрывался тогда, когда нужно). Но обо всем по порядку. Давайте перейдем к самой интересной, на мой взгляд, части — css.
Показать css код
/* скрываем все инпуты, чтобы все выглядело красиво */ input { display: none; } /* стилизуем стандартный текст лейбела(желательно смотреть этот стиль после .items) */ #text { position: absolute; display: block; top: 0; padding-left: 10px; } /* Задаем параметры нашего селекта - ширину, высоту и line-height(для центрирования текста по вертикали;этот парметр меньше ширины на 4px, т.к. в нашем блоке есть border размером в 2px со всех сторон) */ .select { display: inline-block; width: 160px; height: 34px; line-height: 30px; position: relative; } /* Это наша стрелочка, показывающая, что селект можно раскрыть */ .select:before { content: ">"; display: inline-block; background: white; position: absolute; right: -5px; top: 2px; z-index: 2; width: 30px; height: 26px; text-align: center; line-height: 26px; border: 2px solid #ddd; transform: rotate(90deg); cursor: pointer; } /* Если ничего не выбрано, то наш изначальный текст черного цвета, как и должно быть */ .select input[name="list"]:not(:checked) ~ #text { color: black; background: white; } /* Если же что-то выбрано, то наш текст становится невидимым и встает сверху выбранного параметра, чтобы при клике на него можно было заного открыть селект, что не было реализовано прошлым автором */ .select input[name="list"]:checked ~ #text { background: transparent; color: transparent; z-index: 2; } /* Стилизация выключенного селекта */ #select:disabled ~ .items #text { background: #eee; } /* Стилизация блока с опциями. min-height сделана для фикса высоты при абсолютном позиционировании, overflow же сделан для фиксированной высоты(см. ниже) */ .items { display: block; min-height: 30px; position: absolute; border: 2px solid #ddd; overflow: hidden; width: 160px; cursor: pointer; } /* Если наш селект закрыт, то он имеет высоту 30px(сделано для того, чтобы слишком большие надписи не растягивали его в высоту) */ #select:not(:checked) ~ .items { height: 30px; } /* Все лейбелы(названия опций) изначально скрыты */ .items label { border-top: 2px solid #ddd; display: none; padding-left: 10px; background: white; } /* Тут много объяснять не надо - просто выделение при наведении */ .items label:hover { background: #eee; cursor: pointer; } /* Опять же фикс из-за абсолютного позиционирования */ #select:checked ~ .items { padding-top: 30px; } /* Если наш селект открыт, то надо сделать все опции видимыми */ #select:checked ~ .items label { display: block; } /* Если какая-либо опция была выбрана, то сделать ее видимой(при выборе селект автоматически закроется) */ .items input:checked + label { display: block!important; border: none; background: white; } /* При открытии селекта создать подложку во весь экран, при клике на которую селект закроется, а значение останется пустым. background сделан для наглядности */ #select:checked ~ .bg { position: fixed; top: 0; left: 0; bottom: 0; right: 0; z-index: 0; background: rgba(0,0,0,0.4); }
Вот она — самая интересная часть, в которой надо осмыслить как смена выбора инпута (все инпуты с типом радио имеют одинаковое имя => мы можем выбрать только один из них) влияет на наш селект. Еще одной особенностью этого варианта является возможность отключить селект, используя атрибут disabled на #select.
Готовый пример вы можете найти здесь.
Вот, собственно, и все. Парочка минусов предыдущего автора пофикшены, так что это решение, полагаю, на данный момент можно считать идеальным css-вариантом селекта. Надеюсь, мое решение кому-нибудь пригодится.
