Настройка элементов формы всегда была довольно неприятной, и элемент 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) включена по умолчанию. Итак, мы на правильном пути! ?