Настройка элементов формы всегда была довольно неприятной, и элемент select — один из тех элементов, который может заставить вас захотеть вырвать оставшиеся волосы, пытаясь их стилизовать. Как вы, возможно, уже знаете, когда речь идет о его настройке, к нему можно применить не так уж много CSS-элементов, а только такие свойства, как цвет, фон, шрифт или рамку.
В этой статье, чтобы настроить внешний вид выпадающего списка HTML, мы будем использовать другой подход, основанный на некоторых передовых технологиях, таких как @supports, pointer-eventsи appearance.
Посмотреть демо
Необходимость пользовательских выпадающих
Настройки браузера по умолчанию никогда не были достаточными, поэтому веб-разработчики постоянно пытаются расширить границы и возможности, когда дело доходит до настройки собственных элементов HTML. В последнее время мы видели так много пользовательских флажков и радио, пользовательских индикаторов выполнения и многих других, но ничего нового, например, касающегося выпадающего меню или файловых входов.
Имея это в виду и вдохновленный техникой Леа Веру , я решил поделиться с вами своим мнением о настройке раскрывающегося списка HTML. Так же, как заявление об отказе от ответственности, я знаю, что в дикой природе есть множество удивительных плагинов jQuery, которые могут помочь вам создавать красивые и сложные выпадающие списки, но иногда кажется, что это слишком много для раскрывающегося списка.
Разметка
Для начала ниже приведена разметка, необходимая для пользовательского раскрывающегося списка HTML.
<span class="custom-dropdown custom-dropdown--white">
<select class="custom-dropdown__select custom-dropdown__select--white">
<option>The Shawshank Redemption</option>
<option>The Godfather</option>
<option>Pulp Fiction</option>
<option>The Good, the Bad and the Ugly</option>
<option>12 Angry Men</option>
</select>
</span>
Вы можете удивиться, почему я выбрал spanв качестве обертки, а не тот, labelкоторый может показаться более подходящим. Причина в том, что мы не хотим тратить функциональность метки только на эту настройку. Кроме того, таким образом вы все еще можете обернуть все внутри метки, чтобы улучшить удобство использования следующим образом:
<label> IMDB Top Movies: <span class="custom-dropdown custom-dropdown--white"> <select class="custom-dropdown__select custom-dropdown__select--white"> <option>The Shawshank Redemption</option> <option>The Godfather</option> <option>Pulp Fiction</option> <option>The Good, the Bad and the Ugly</option> <option>12 Angry Men</option> </select> </span> </label>
Соглашение об именах БЭМ
Если вы заметили пространство имен, я использую соглашение об именах БЭМ, которое, я уверен, вы видели раньше. Излишне говорить, что это камни!
(Block) .custom-dropdown = The main component (Element) .custom-dropdown__select = Descendant of .custom-dropdown (Modifier) .custom-dropdown--* = Different state of .custom-dropdown
CSS
Проверьте стили ниже, чтобы увидеть, как все работает. @supportsПравило делает всю магию:
.custom-dropdown--large {
font-size: 1.5em;
}
.custom-dropdown--small {
font-size: .7em;
}
.custom-dropdown__select{
font-size: inherit; /* inherit size from .custom-dropdown */
padding: .5em; /* add some space*/
margin: 0; /* remove default margins */
}
.custom-dropdown__select--white {
background-color: #fff;
color: #444;
}
@supports (pointer-events: none) and
((-webkit-appearance: none) or
(-moz-appearance: none) or
(appearance: none)) {
.custom-dropdown {
position: relative;
display: inline-block;
vertical-align: middle;
}
.custom-dropdown__select {
padding-right: 2.5em; /* accommodate with the pseudo elements for the dropdown arrow */
border: 0;
border-radius: 3px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.custom-dropdown::before,
.custom-dropdown::after {
content: "";
position: absolute;
pointer-events: none;
}
.custom-dropdown::after { /* Custom dropdown arrow */
content: "\25BC";
height: 1em;
font-size: .625em;
line-height: 1;
right: 1.2em;
top: 50%; margin-top: -.5em;
}
.custom-dropdown::before { /* Custom dropdown arrow cover */
width: 2em;
right: 0; top: 0; bottom: 0;
border-radius: 0 3px 3px 0;
}
.custom-dropdown__select[disabled] {
color: rgba(0,0,0,.3);
}
.custom-dropdown.custom-dropdown--disabled::after {
color: rgba(0,0,0,.1);
}
/* White dropdown style */
.custom-dropdown--white::before {
top: .5em; bottom: .5em;
background-color: #fff;
border-left: 1px solid rgba(0,0,0,.1);
}
.custom-dropdown--white::after {
color: rgba(0,0,0,.9);
}
/* FF only temp fix */
@-moz-document url-prefix() {
.custom-dropdown__select { padding-right: .9em }
.custom-dropdown--large .custom-dropdown__select { padding-right: 1.3em }
.custom-dropdown--small .custom-dropdown__select { padding-right: .5em }
}
}
Резюме
На первый взгляд, CSS может показаться слишком сложным, поэтому давайте разберем его.
внешность
appearance: noneДекларация используется здесь , чтобы сбросить внешний вид по умолчанию для нативного выпадающего списка. Это appearanceсвойство очень полезно, когда вы хотите добавить конкретный стиль к элементу, который не имеет его по умолчанию, или полностью удалить конкретный стиль, как в этом случае.
Возможно, вы видели выше это правило CSS: @-moz-document url-prefix()ну, это хак для браузеров Firefox . В Firefox есть довольно старая ошибка, связанная с тем, как она appearance: noneработает , но она заключается в том, что, хотя appearance: noneкажется, что она работает, нативная стрелка раскрывающегося списка все еще показывает.
Итак, временное решение состоит в том, чтобы в основном покрыть нативную стрелку раскрывающегося списка:
@-moz-document url-prefix() {
...
}
::до после
Применив вышеупомянутое объявление, которое очищает внешний вид по умолчанию, выпадающий треугольник сделан с использованием псевдоэлементов . Здесь не так много, чтобы сказать, вы знаете, псевдо, они есть везде. ?
указатель событий
Если вы не знакомы с этим pointer-events, вы должны знать, что с pointer-events: noneпомощью наиболее часто встречающегося объявления вы можете, например, удалить события мыши для навигации по текущей странице. В этом случае мы удалили события мыши для псевдоэлемента прямоугольного треугольника, чтобы избежать проблем с доступностью.
В качестве побочного эффекта, если элемент был pointer-events: noneприменен, его состояние наведения больше не может быть стилизовано.
@supports
И последнее, но не менее важное: последнее @supportsправило помогает обнаруживать функции CSS. Обнаружение функций с использованием JavaScript не является чем-то новым, и Modernizr — лучший пример здесь. Итак, если вы уже слышали о Modernizr, подумайте о @supportsправиле как о его CSS-эквиваленте.
Чтобы предотвратить несоответствия браузеров, следующее правило позволяет настраивать таргетинг только на те браузеры, которые поддерживают оба pointer-eventsварианта appearance. Лучшими примерами здесь являются браузеры IE9 и IE10, которые поддерживают множество CSS3-компонентов из приведенного выше кода, но не поддерживают (пока) передовые технологии, такие как pointer-eventsили appearanceкоторые делают эту технику неэффективной.
@supports (pointer-events: none) and
((-webkit-appearance: none) or
(-moz-appearance: none) or
(appearance: none)) {
...
}
Немного JavaScript
Правда заключается в том, что вы можете использовать только ключевое слово CSS, чтобы назвать это решение по стилю. Но, чтобы охватить также случай, когда выборка отключена, вам понадобится JS, чтобы нацелиться на родительский узел и применить класс HTML, например custom-dropdown--disabled.
<script>
(function(){
/*1*/var customSelects = document.querySelectorAll(".custom-dropdown__select");
/*2*/for(var i=0; i<customSelects.length; i++){
if (customSelects[i].hasAttribute("disabled")){
customSelects[i].parentNode.className += " custom-dropdown--disabled";
}
}
})()
</script>
- Возвращает список элементов в документе, которые совпадают
.custom-dropdown__select. - Для каждого отключенного выбора перейдите на его родительский узел и добавьте
custom-dropdown--disabledкласс HTML. Таким образом, мы сможем использовать CSS для настройки стрелки, когда выбор отключен.
Конечно, ничего из вышеперечисленного не потребуется, если элемент select, который является заменяемым элементом , разрешил бы на нем псевдоэлементы или если бы существовал родительский селектор CSS . Но это другая история. ?
На поддержку браузера
Насколько я тестировал, демо работает на Firefox Nightly / Aurora , Chrome Canary и Opera Next . Кроме того, это означает, что очень скоро вы сможете увидеть, как это работает и в версиях выпуска, учитывая, как часто запускаются новые версии браузера. Проверьте таблицу совместимости для поддержки CSS Feature Queries в настольных и мобильных браузерах.
Посмотреть демо
Помимо вышеупомянутых версий браузеров, при подготовке к публикации этой статьи, Firefox 22 только что запустил. И угадайте, что? Поддержка условных выражений CSS (@supports и CSS.supports) включена по умолчанию. Итак, мы на правильном пути! ?

