Как изменить стиль select css

Когда речь заходит о кастомизации полей формы, наибольшую сложность представляет стилизация HTML-элемента select. В этом случае разработчики часто обращаются за библиотекой или фреймворком, в которых не всегда удачно и в полном объёме воспроизводится вся функциональность нативного элемента управления. Если не брать во внимание суждения о ценности элементов управления select или подобных им, можно констатировать факт:

Когда речь заходит о кастомизации полей формы, наибольшую сложность представляет стилизация HTML-элемента select. В этом случае разработчики часто обращаются за библиотекой или фреймворком, в которых не всегда удачно и в полном объёме воспроизводится вся функциональность нативного элемента управления.

Если не брать во внимание суждения о ценности элементов управления select или подобных им, можно констатировать факт: полностью воссоздать их функции, учесть все нюансы поведения и сохранить доступность для людей с ограниченными возможностями — гиперсложная задача.

Ниже будет показано, что и как можно сделать с внешним видом select с помощью обычного CSS, оставаясь в рамках требований WCAG к доступности (читаемость, контрастность, пользовательские настройки), а также вариантов написания: справа-налево и слева-направо.

Основные стили

Сперва сбросим параметры текста.

select {
  font: inherit;
  letter-spacing: inherit;
  word-spacing: inherit;
}

font

Свойство font наследует все стили от контейнера(ов). Иногда при сбросе CSS указывают размер шрифта font-size, но в этом нет необходимости. font будет наследовать стили всех своих параметров: font-size, font-family, font-style, font-variant, font-weight, font-stretch и font-height (если установлено). Ещё он добавляет высоту строки line-height. В-общем, шрифт будет адаптироваться к изменениям, которые касаются всей страницы, либо с помощью надстроек, либо через настройки браузера/системы.

letter-spacing

Если пользователь (или автор) изменяет параметры текста, чтобы повлиять на расстояние между буквами, это не будет касаться предустановленных для поля значений. Наследование параметров font не повлияет на межбуквенное расстояние, поэтому нужно явно указать необходимость наследования значения letter-spacing: inherit. Это поможет соответствовать требованиям WCAG 2.1 Success Criterion 1.4.12: Text Spacing

word-spacing

Аналогично межбуквенному letter-spacing, значение word-spacing для управления интервалами между словами не будет наследоваться, если это не объявить явным образом. WCAG 1.4.12 применяется и для расстояния между словами.

line-height

Обратите внимание, что в коде не устанавливается высота строки line-height. Это значение нормально наследуется вместе с остальными параметрами шрифта в свойстве font. Если обнаружится, что это не так (например, из-за явной установки высоты строки ) можно добавить line-height: inherit, чтобы соответствовать WCAG 1.4.12.

Пример

В этом примере демонстрируется применение этого минимального набора стилей.

See this code Простой Select on x.xhtml.ru.

Как настроить стрелку для select

Часто, стрелка (индикатор того, что это выпадашка — поле выбора значений) по умолчанию плохо вписывается в дизайн и её лучше заменить на что-нибудь более подходящее. Вот необходимый минимум стилей, с помощью которых можно заменить стрелку у select:

select {
  font: inherit;
  letter-spacing: inherit;
  word-spacing: inherit;
  -moz-appearance: none;
  -webkit-appearance: none;
  appearance: none;
}

select:not([multiple]) {
  padding-right: 1.2em;
  background-repeat: no-repeat;
  background-position: calc(100% - 0.25em) 0.35em;
  background-size: 0.85em auto;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 80'%3E%3Cpath d='M70.3 13.8L40 66.3 9.7 13.8z' fill='%23000'%3E%3C/path%3E%3C/svg%3E");
}

/* скроет иконку стрелки в IE */
select::-ms-expand {
  display: none;
}

Здесь удаляются стили, устанавливаемые браузером, освобождается место для графической стрелки, а затем новая картинка стрелки вставляется в качестве фона. Это должно применяться только в том случае, если select обычный и предназначен для выбора одиночного значения, а не нескольких (multiple).

See this code Select с измененной стрелкой on x.xhtml.ru.

Этот пример демонстрирует замену стрелки по умолчанию элементу select.

Продолжение настройки select

Стоит обратить внимание, что интервалы у текста не очень хороши. Потенциально можно сделать их более привлекательными, удобными и доступными для пользователей с помощью всего нескольких дополнительных стилей. Например, можно настроить border и padding. Эти два свойства расширяют базовые стили, описанные выше, чтобы сделать текстовые поля более удобными.

select {
  font: inherit;
  letter-spacing: inherit;
  word-spacing: inherit;
  -moz-appearance: none;
  -webkit-appearance: none;
  appearance: none;
  /* рамка и отступы */
  border: 0.1em solid;
  padding: 0 0.2em;
}

border

Изменение значений CSS-свойств для рамки поля сопряжено с риском. Согласно WCAG (SC 1.4.11: Non-text Contrast), если для элемента формы не вносить изменений в стили по умолчанию, то это никак не повлияет на контрастность. Тем не менее, с помощью border: 0.1em solid будет установлена толщина рамки на основе размера шрифта. Теперь рамка поля выбора будет масштабироваться вместе с текстом. Заодно она становится толще, чем используется по умолчанию в большинстве браузеров.

Здесь умышленно не установлен цвет рамки, чтобы позволить браузеру сделать это самостоятельно. Конечно, если фон страницы не белый, можно изменить цвет рамки.

padding

Трогать padding для select не обязательно. Однако, содержимое поля будет немного легче читать и использовать, если немного его настроить. Это поможет сделать отступы в select ближе к аналогичным в textarea и input, если их тоже предстоит настраивать.

Стилизация состояний select

Поля формы могут находиться в разных состояниях. Отключенное, сфокусированное, с ошибкой и обязательное — это наиболее распространенные состояния, которые можно применить к элементам управления. Не обязательно применять какие-либо из предлагаемых стилей, но можно использовать селекторы и логику, лежащие в их основе, чтобы реализовать состояния в собственной библиотеке шаблонов.

Отключено disabled

Отключенные поля исключаются из требований к контрастности WCAG, как и элементы управления интерфейса по умолчанию. Если ничего не делать, браузер самостоятельно сделает всё необходимое. Поэтому здесь не стоит что-то менять в настройках цвета фона поля или текста, достаточно позволить браузеру выполнить эту работу по его усмотрению.

Сфокусировано focused

WCAG SC 2.4.7 не рекомендует здесь ничего делать, согласно Technique G149, потому что браузер добавляет свой собственный стиль для фокуса. Тем не менее, можно сделать его ещё более очевидным, например, использовать синий контур с хорошим контрастом к белому и добавить тень:

select:focus {
  outline: 0.15em solid #00f;
  box-shadow: 0 0 0.2em #00f;
}

Только для чтения readonly

Нативный элемент <select> не поддерживает атрибут readonly.

Обязательное поле required

Пока label указывает, что поле обязательное (вместе с атрибутом required), нет большой необходимости стилизовать select как-то особенно. Но, например, можно увеличить обязательному полю толщину границы слева. В совокупности с оформлением других полей это может дать достаточно информации. Можно не менять цвет рамки, позволяя наследование (по умолчанию от стилей пользовательского агента).

select[required] {
  border-left-width: 0.3em;
}

Поле с ошибками

Одной красной рамки тут будет недостаточно (из-за сбоев WCAG по контрасту и только по цвету), а массивные тени могут испачкать всю страницу. Слишком много усилий по привлечению внимания к ошибкам создают шум, требующий от пользователей больших усилий для их устранения. Вместо этого можно добавить небольшой индикатор в углу поля. Градиент, образующий красную метку, устанавливает белый цвет фона поля. Обратите внимание, здесь в первый раз полю select явно задаётся цвет фона.

Здесь не будет использоваться селектор :invalid, потому что он может негативно влиять на нативное представление ошибок в браузере. Вместо этого можно использовать наличие-отсутствие aria-invalid, не просто переключая его с true на false, а добавляя или удаляя этот атрибут. Поскольку стрелка, как было решено выше, также является фоновым изображением, её здесь придётся повторно установить, если речь об обычном select без множественного выбора (multiple).

select[aria-invalid] {
  background: linear-gradient(
    135deg,
    rgba(255, 0, 0, 1) 0,
    rgba(255, 0, 0, 1) 0.4em,
    rgba(255, 255, 255, 0) 0.4em
  );
}

select[aria-invalid]:not([multiple]) {
  background-repeat: no-repeat, no-repeat;
  background-position: 0 0, calc(100% - 0.25em) 0.35em;
  background-size: 0.85em auto;
  background-image: linear-gradient(
      135deg,
      rgba(255, 0, 0, 1) 0,
      rgba(255, 0, 0, 1) 0.4em,
      rgba(255, 255, 255, 0) 0.4em
    ),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 80'%3E%3Cpath d='M70.3 13.8L40 66.3 9.7 13.8z' fill='%23000'%3E%3C/path%3E%3C/svg%3E");
}

Стили для интернационализации

Чтобы не сильно усложнять, здесь речь пойдёт только о стилях написания справа налево, а при необходимости, будет не трудно разобраться и адаптировать это.

Для нативного поля выбора select достаточно поправить только стили, которые написаны, исходя из ожиданий для языков с написанием слева направо, а именно: стрелка, индикаторы обязательности и ошибки, которые позиционируются в зависимости от того, с какой стороны пользователь начинает читать. Здесь достаточно переместить стрелку, красную метку и более толстую границу на противоположную сторону.

*[dir="rtl"] select:not([multiple]) {
  padding-right: 0.2em;
  padding-left: 1.2em;
  background-position: 0.25em 0.35em;
}

*[dir="rtl"] select[required] {
  border-left-width: 0.1em;
  border-right-width: 0.3em;
}

*[dir="rtl"] select[aria-invalid] {
  background: linear-gradient(
    225deg,
    rgba(255, 0, 0, 1) 0,
    rgba(255, 0, 0, 1) 0.4em,
    rgba(255, 255, 255, 0) 0.4em
  );
}

*[dir="rtl"] select[aria-invalid]:not([multiple]) {
  background: linear-gradient(
    225deg,
    rgba(255, 0, 0, 1) 0,
    rgba(255, 0, 0, 1) 0.4em,
    rgba(255, 255, 255, 0) 0.4em
  ),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 80'%3E%3Cpath d='M70.3 13.8L40 66.3 9.7 13.8z' fill='%23000'%3E%3C/path%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: auto, 0.85em auto;
  background-position: 0 0, 0.25em 0.35em;
}

Стили режима высокой контрастности Windows

Поскольку используются нативные элементы управления, нет вмешательства в цвета и стили для критически важных функций, которые отсутствуют в WHCM, т.е. в основном были применены системные стили — в этом направлении особо ничего делать не нужно.

Стиль подсветки контура outline здесь хорошо адаптируется. Переключение в disabled работает, как и должно по умолчанию. Стили border не затрагивают цвет и не повлияют работу с любой контрастностью.

Единственное, что может теряться — это индикация ошибки. При таком небольшом количестве цветов (система WHCM) может понадобиться акцент на другом визуальном индикаторе ошибок. Например, использовать label, чтобы четко указать на ошибки.

Стили для печати

Толщина границы масштабируется в зависимости от размера шрифта — это можно игнорировать. Пользователь, скорее всего, выберет размер шрифта, который будет разборчивым. Фоном отключенных полей и полей с ошибками можно управлять в настройках печати. Размер текста для поля не изменялся, наследуется. Здесь ничего не надо делать.

Стили для тёмного режима (dark mode)

Тёмный режим — это функциональный запрос, который нужно создать для поддержки стилей. Здесь не будет примера, а только рекомендации. Достаточно выбрать цвет фона и цвет шрифта и не писать все новые стили с нуля.

Следует наследовать цвет текста и фон (или сделать его прозрачным) и выбрать цвет рамки, который по-прежнему соответствует требованиям контрастности. Стили состояния при фокусировке тоже нуждаются в достаточном контрасте. Метка для состояния при ошибке зависит от фонового градиента к белому, поэтому нужно будет полностью переопределить стили ошибок, в том числе для RTL. Отключенные (disabled) поля также потребуют некоторой работы, так как явно заданы цвета границ и текста.

Заключение

Пример стилизованного select в разных состояниях с сохранением WCAG-доступности.

See this code Select Menus on x.xhtml.ru.

Когда речь идет о стилизации полей формы, нужно обратить внимание на минимальный набор стилей, который понадобится, чтобы обеспечить соответствие общему дизайну и поддержку состояний, которые перечислены выше.

Похожие публикации, посвященные стилизации HTML-элемента select: Select Like It’s 2019 и Custom Select Styles with Pure CSS немного отличаются подходами, но заслуживают не меньшего внимания. Может быть эти варианты даже лучше соответствуют вашим целям и требованиям.

Under-Engineered Select Menus.

Пользовательские стили элементов select на CSS

От автора: современный CSS предоставляет нам ряд свойств для создания пользовательских стилей элемента select, которые имеют почти идентичный начальный вид для одиночных, множественных и отключенных элементов select в популярных браузерах.

Несколько свойств и методов, которые будет использовать наше решение:

clip-path для создания настраиваемой стрелки раскрывающегося списка

макет сетки CSS для выравнивания пользовательского поля выбора и стрелки

пользовательские переменные CSS для гибкого стиля

Практический курс по верстке адаптивного сайта с нуля!

Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3

Узнать подробнее

единицы em для относительных размеров

Распространенные проблемы с нативным select

Как и для всех типов полей формы, у select первоначальный вид в разных браузерах различается. Слева направо, вот исходный вид select в Firefox, Chrome и Safari:

Пользовательские стили элементов select на CSS

Различия включают в себя размер поля, размер шрифта, высоту строки, и наиболее выдающейся является разница в стиле раскрывающегося индикатора. Наша цель — создать в этих браузерах одинаковый исходный вид, включая множественный выбор и отключенные состояния.

Примечание. Раскрывающийся список по-прежнему не стилизован, поэтому после select он все равно подберет для этого варианта список стилей отдельных браузеров . Это нормально — мы можем справиться с этим, чтобы сохранить доступность нативного select!

Базовый HTML

Для начала мы сосредоточимся на одиночном select.

<label for=«standard-select»>Standard Select</label>

<div class=«select»>

  <select id=«standard-select»>

    <option value=«Option 1»>Option 1</option>

    <option value=«Option 2»>Option 2</option>

    <option value=«Option 3»>Option 3</option>

    <option value=«Option 4»>Option 4</option>

    <option value=«Option 5»>Option 5</option>

    <option value=«Option length»>Option that has too long of a value to fit</option>

  </select>

</div>

Метка не является частью нашего упражнения, но включена в общем требовании, в частности, с атрибутом for, имеющим значение свойства id для select.

Чтобы реализовать наши пользовательские стили, мы для простоты в этом руководстве заключили пользовательский select в дополнительный div с классом select.

Сбросить и удалить унаследованные стили

Как и во всех моих руководствах в качестве передовой современной практики, мы сначала добавляем следующий сброс:

*,

*::before,

*::after {

  box-sizing: border-box;

}

После этого мы можем начать правило для нативного select и применить следующее к его внешнему виду:

select {

  // A reset of styles, including removing the default dropdown arrow

  appearance: none;

  // Additional resets for further consistency

  background-color: transparent;

  border: none;

  padding: 0 1em 0 0;

  margin: 0;

  width: 100%;

  font-family: inherit;

  font-size: inherit;

  cursor: inherit;

  line-height: inherit;

}

Хотя большинство из этих стилей вам, вероятно, знакомы, странность заключается в appearance. Это редко используемое свойство, и вы заметите, что это не совсем то место, где мы хотели бы его поддерживать, но в этом случае оно в первую очередь обеспечивает нам удаление стрелки раскрывающегося списка.

Примечание: CodePen настроен на использование автопрефикса, который добавит необходимые предварительно фиксированные версии свойства appearance. Возможно, вам придется специально настроить это для своего проекта или добавить их вручную. Мой HTML / Sass Jumpstart включает автопрефиксатор, как часть производственной сборки.

Хорошая новость в том, что мы можем добавить еще одно правило, чтобы убрать стрелку для более ранних версий IE, если вам это нужно:

select::-ms-expand {

  display: none;

}

Последняя часть — удалить значение по умолчанию outline. Не волнуйтесь — позже мы добавим ему замену для состояния :focus!

select {

  // …existing styles

  outline: none;

А вот гифка нашего прогресса. Вы можете видеть, что теперь нет визуальной индикации того, что это select до того, как кликнуть по нему:

Пользовательские стили элементов select на CSS

Пользовательские стили поля выбора

Сначала давайте настроим некоторые переменные CSS. Это позволит гибко перекрашивать наш select, чтобы отображать состояние ошибки.

:root {

  —select-border: #777;

  —select-focus: blue;

  —select-arrow: var(—select-border);

}

Примечание для специальных возможностей: как элемент пользовательского интерфейса выделенная граница должна иметь контраст 3:1 или выше по сравнению с цветом окружающего пространства.

Теперь пришло время создать стили select, которые мы применим к нашей оболочке div.select:

.select {

  width: 100%;

  min-width: 15ch;

  max-width: 30ch;

  border: 1px solid var(—select-border);

  border-radius: 0.25em;

  padding: 0.25em 0.5em;

  font-size: 1.25rem;

  cursor: pointer;

  line-height: 1.1;

  background-color: #fff;

  background-image: linear-gradient(to top, #f9f9f9, #fff 33%);

}

Сначала мы устанавливаем некоторые ограничения по ширине. Значения min-width и max-width в основном предназначены для этой демонстрации, и вы можете отказаться от них или изменить их для своего варианта использования.

Затем мы применяем некоторые свойства блочной модели, в том числе border, border-radius и padding. Обратите внимание на использование единицы em, которая будет сохранять эти свойства пропорциональными набору font-size.

В сбросе стилей, мы установили для нескольких свойств inherit, так что здесь мы определяем их, в том числе font-size, cursor и line-height.

Наконец, мы предоставляем свойства фона, включая градиент для малейшего размера. Если вы удалите свойства фона, выделение станет прозрачным и сохранит фон страницы. Это может быть желательно, однако помните о влияние на контраст и проверяйте его. И вот наш прогресс:

Пользовательские стили элементов select на CSS

Пользовательская стрелка раскрывающегося списка выбора

Для нашей стрелки раскрывающегося списка, мы будем использовать одно из самых интересных современных свойств CSS: clip-path.

Обрезка контуров позволяет нам создавать всевозможные формы, «обрезая» квадратные и прямоугольные фигуры, которые мы получаем по умолчанию от большинства элементов. Я получил удовольствие от использования clip-path при моем недавнем редизайне сайта-портфолио.

До получения лучшей поддержки clip-path альтернативные методы включали:

background-image — обычно в формате PNG, более современным будет SVG

встроенный SVG как дополнительный элемент

трюк границы, чтобы создать треугольник

SVG может показаться оптимальным решением, однако при использовании в background-image в качестве иконки он теряет способность действовать как иконка в том смысле, что не может изменять свои свойства, такие как цвет заливки, без его полного переопределения. Это означает, что мы не можем использовать переменную CSS.

Размещение встроенного SVG-файла решает проблему с цветом, однако это означает добавление еще одного элемента каждый раз, когда определяется select.

С помощью clip-path мы получаем четкую, масштабируемую «графику» стрелки, которая выглядит как SVG, но с преимуществами возможности использовать пользовательскую переменную и определения через стили вместо разметки HTML. Чтобы создать стрелку, мы определим ее как псевдо-элемент ::after.

.select::after {

  content: «»;

  width: 0.8em;

  height: 0.5em;

  background-color: var(—select-arrow);

  clip-path: polygon(100% 0%, 0 0%, 50% 100%);

}

Если вы следите по тексту, возможно, вы заметили, что стрелка не отображается, несмотря на определение width и height. При осмотре было обнаружено, что для ::after ширина на самом деле не разрешена. Мы решим эту проблему, обновив .select макетом сетки CSS.

.select {

  // …existing styles

  display: grid;

}

Практический курс по верстке адаптивного сайта с нуля!

Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3

Узнать подробнее

Это позволяет стрелке отображаться.

Пользовательские стили элементов select на CSS

На этом этапе мы можем видеть, что у нас действительно есть треугольник. Чтобы исправить выравнивание, мы воспользуемся моим любимым приемом CSS-сетки. Старое решение CSS: position: absolute. Новое решение CSS: единая grid-template-areas, содержащая их все.

Сначала мы определим область, а затем определим, что и select, и ::after используют ее. Имя привязано к элементу, для которого он создан, и мы упростим все, назвав его «select»:

.select {

  // …existing styles

  grid-template-areas: «select»;

}

select,

.select:after {

  grid-area: select;

}

Это дает нам перекрытие стрелкой пользовательского select из-за контекста стекирования:

Пользовательские стили элементов select на CSS

Теперь мы можем использовать свойства сетки для завершения выравнивания каждого элемента:

.select {

  // …existing styles

  align-items: center;

}

.select:after {

  // …existing styles

  justify-self: end;

}

Пользовательские стили элементов select на CSS

Состояние :focus

Ах да — помните, как мы удалили outline? Нам нужно исправить отсутствующее состояние :focus. В ближайшее время мы могли бы использовать свойство :focus-within, но все же на данный момент лучше включить для него полифилл.

В этом руководстве мы будем использовать альтернативный метод, который дает тот же результат, только немного посложнее. К сожалению, это означает, что нам нужно добавить в DOM еще один элемент. После пользовательского элемента select в качестве последнего дочернего элемента внутри .select добавьте:

<span class=«focus»></span>

Почему после? Поскольку, это решение на чистом CSS, размещение его после пользовательского select означает, что мы можем изменить его, когда select выделен фокусом, используя селектор — +. Это позволяет нам создать следующее правило:

select:focus + .focus {

  position: absolute;

  top: -1px;

  left: -1px;

  right: -1px;

  bottom: -1px;

  border: 2px solid var(—select-focus);

  border-radius: inherit;

}

Вам может быть интересно, почему мы вернулись к position: absolute после того, как только что изучили прием grid-area. Причина в том, что мы хотим избежать пересчета корректировок на основе заполнения. Если вы попробуете это самостоятельно, то увидите, что даже указание для width и height 100% все равно заставляет его находиться внутри отступа.

position: absolute работает лучше. Мы растягиваем лишний пиксель в каждом направлении, чтобы убедиться, что он перекрывает границу.

Но нам нужно сделать еще одно добавление, чтобы обеспечить, что .select связано с нашим select… ну, через position: relative.

.select {

  // …existing styles

  position: relative;

И вот как отображается в Chrome наш пользовательский select:

Пользовательские стили элементов select на CSS

Множественный выбор

Элемент выбора имеет второй вариант, который позволяет пользователю выбрать более одной опции. С точки зрения HTML это просто означает добавление атрибута multiple, но мы также добавим класс, который поможет создавать настройки стиля, select—multiple:

<label for=«multi-select»>Multiple Select</label>

<div class=«select select—multiple»>

  <select id=«multi-select» multiple>

    <option value=«Option 1»>Option 1</option>

    <option value=«Option 2»>Option 2</option>

    <option value=«Option 3»>Option 3</option>

    <option value=«Option 4»>Option 4</option>

    <option value=«Option 5»>Option 5</option>

    <option value=«Option length»>Option that has too long of a value to fit</option>

  </select>

  <span class=«focus»></span>

</div>

И глядя на него, мы видим, что он унаследовал большинство наших стилей, за исключением того, что нам не нужна стрелка в этом представлении.

Пользовательские стили элементов select на CSS

Это можно быстро исправить. Мы используем :not(), чтобы исключить наш недавно определенный класс:

.select:not(.select—multiple)::after

У нас есть пара незначительных корректировок для множественного выбора, первая — это удаление отступов, которые были добавлены ранее, чтобы освободить место для стрелки:

select[multiple] {

  padding-right: 0;

}

По умолчанию опции с длинным значением будут выходить за пределы видимой области и будут обрезаны, но я обнаружил, что основные браузеры позволяют переопределить перенос, если вы хотите:

select[multiple] option {

  white-space: normal;

}

Опционально мы можем установить для select свойство height, чтобы обеспечить более надежное кроссбраузерное поведение. В ходе тестирования я узнал, что Chrome и Firefox отображают опцию частично, но Safari полностью скроет опцию, которая не может быть отображена полностью.

Высота должна быть установлена непосредственно для пользовательского select. Учитывая другие стили, значение 6rem должно подойти для отображения 3 опций:

select[multiple] {

  // …existing styles

  height: 6rem;

}

На данный момент, из-за текущей поддержки браузеров, мы внесли столько корректировок, сколько смогли. Состояние :selected из options довольно хорошо настраивается в Chrome, частично в Firefox, и совсем не настраивается в Safari.

Стили :disabled

Хотя я бы выступала за то, чтобы просто не отображать отключенные элементы управления, мы должны подготовить стили для этого состояния, чтобы охватить все.

Чтобы выделить отключенное состояние, нам нужно применить серый фон. Но поскольку мы установили стили фона .select, и селектора :parent нет, нам нужно создать последний класс для обработки этого состояния:

.select—disabled {

  cursor: not-allowed;

  background-color: #eee;

  background-image: linear-gradient(to top, #ddd, #eee 33%);

}

Здесь мы обновили курсор как дополнительную подсказку о том, что с полем нельзя взаимодействовать, и обновили значения для фона, которые мы ранее установили, как белый, теперь они более серые для отключенного состояния. Это дает нам:

Пользовательские стили элементов select на CSS

Демо

Вы можете проверить это сами, но вот предварительный просмотр полного решения (слева направо) в Firefox, Chrome и Safari:

Пользовательские стили элементов select на CSS

Автор: Stephanie Eckles

Источник: //moderncss.dev

Редакция: Команда webformyself.

Практический курс по верстке адаптивного сайта с нуля!

Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3

Узнать подробнее

PSD to HTML

Практика верстки сайта на CSS Grid с нуля

Смотреть

Here are three solutions:

Solution #1 — appearance: none — with Internet Explorer 10 — 11 workaround (Demo)

To hide the default arrow set appearance: none on the select element, then add your own custom arrow with background-image

select {
   -webkit-appearance: none;
   -moz-appearance: none;
   appearance: none;       /* Remove default arrow */
   background-image: url(...);   /* Add custom arrow */
}

Browser Support:

appearance: none has very good browser support (caniuse) — except for Internet Explorer.

We can improve this technique and add support for Internet Explorer 10 and Internet Explorer 11 by adding

select::-ms-expand {
    display: none; /* Hide the default arrow in Internet Explorer 10 and Internet Explorer 11 */
}

If Internet Explorer 9 is a concern, we have no way of removing the default arrow (which would mean that we would now have two arrows), but, we could use a funky Internet Explorer 9 selector.

To at least undo our custom arrow — leaving the default select arrow intact.

/* Target Internet Explorer 9 to undo the custom arrow */
@media screen and (min-width:0) {
    select {
        background-image:none9;
        padding: 5px9;
    }
}

All together:

This solution is easy and has good browser support — it should generally suffice.


If browser support for Internet Explorer is needed, read ahead.

Solution #2 Truncate the select element to hide the default arrow (demo)

(Read more here)

Wrap the select element in a div with a fixed width and overflow:hidden.

Then give the select element a width of about 20 pixels greater than the div.

The result is that the default drop-down arrow of the select element will be hidden (due to the overflow:hidden on the container), and you can place any background image you want on the right-hand-side of the div.

The advantage of this approach is that it is cross-browser (Internet Explorer 8 and later, WebKit, and Gecko). However, the disadvantage of this approach is that the options drop-down juts out on the right-hand-side (by the 20 pixels which we hid… because the option elements take the width of the select element).

Enter image description here

[It should be noted, however, that if the custom select element is necessary only for mobile devices — then the above problem doesn’t apply — because of the way each phone natively opens the select element. So for mobile, this may be the best solution.]


If the custom arrow is necessary on Firefox — prior to Version 35 — but you don’t need to support old versions of Internet Explorer — then keep reading…

Solution #3 — Use the pointer-events property (demo)

(Read more here)

The idea here is to overlay an element over the native drop down arrow (to create our custom one) and then disallow pointer events on it.

Advantage: It works well in WebKit and Gecko. It looks good too (no jutting out option elements).

Disadvantage: Internet Explorer (Internet Explorer 10 and down) doesn’t support pointer-events, which means you can’t click the custom arrow. Also, another (obvious) disadvantage with this method is that you can’t target your new arrow image with a hover effect or hand cursor, because we have just disabled pointer events on them!

However, with this method you can use Modernizer or conditional comments to make Internet Explorer revert to the standard built in arrow.

NB: Being that Internet Explorer 10 doesn’t support conditional comments anymore: If you want to use this approach, you should probably use Modernizr. However, it is still possible to exclude the pointer-events CSS from Internet Explorer 10 with a CSS hack described here.

Время прочтения
6 мин

Просмотры 66K

Стилизация некоторых стандартных элементов — довольно нетривиальная задача.

Разумеется, хороший специалист может стилизовать что угодно, однако всё упирается в сложность этого действия.

Для стилизации радиокнопок и чекбоксов потребуется совсем немного времени — идея стилизации label со скрытыми input не нова, и давно и повсеместно используется.

Для стилизации остального — есть JavaScript.

Сегодня я хочу рассказать Вам о том, как можно относительно просто стилизовать выпадающие списки, с минимальным кодом JavaScript (от 0 до 26 строк) и минимальной дополнительной разметкой HTML.

Easy selects withoud JavaScript (almost)

На днях у меня, как это часто и бывает, возникла необходимость стилизовать выпадающий список. Однако именно выпадающим списком он становился только в мобильной версии, до этого же он вёл себя как самая обычная группа радиокнопок.

И вот, когда я уже почти закончил писать очередную жуткую конструкцию, призванную заменить несчастный Select, у меня возник вопрос:

А зачем?

Обычно этот вопрос ведёт к умудрённой прокрастинации, переосмыслению жизни и т.д., но в этот раз что-то пошло не так, и я понял, что вопрос и правда был хорошим, а главное — полезным.


Небольшой ликбез:

Итак, для тех, кто в танке, а также тех, кому выпадающие списки доставили столько боли, что они решили забыть о них, как о страшном сне, я немножко (правда) напомню о том, что это такое.

Выпадающие списки состоят из 2 основных элементов:

  1. Select — контейнер для всего списка
  2. Option — элемент списка

Иногда используется ещё и OptGroup (группа элементов списка), но его реализация пока что остаётся на JavaScript’е.

Основной функционал выпадающего списка — отправка информации о выбранном(ых) пункте(ах) на сервер.

Для полноты картины, вот список атрибутов элементов (чтобы можно было оценить, сколько из них будут реализованы):

  1. Selectdisabled, form, multiple, name, required, size
  2. Optiondisabled, label, selected, value

На этом, пожалуй, закончим с описанием, и перейдём к реализации.


Уже было написано немало слов, поэтому — ближе к коду:

<form>
  <div class="content">
    <h3 class="title">Описание 0 пункта</h3>

    <input id="selectName0" type="radio" value="0" name="selectName" />
    <label for="selectName0">Описание 0 пункта</label>
    <input id="selectName1" type="radio" value="1" name="selectName" />
    <label for="selectName1">Описание 1 пункта</label>
    <input id="selectName2" type="radio" value="2" name="selectName" />
    <label for="selectName2">Описание 2 пункта</label>
  </div>
</form>

Итак, чем же хорош этот код? (всё, без чего можно обойтись при объяснении, убрано специально)

Давайте отметим, какие пункты из функционала Select и Option автоматически стали возможны, за счёт использования input + label:

  1. Select — form, name, required
  2. Option — disabled, label, selected, value

И вот всё, что остаётся реализовать:

  1. Select — disabled, multiple, size
  2. Option — полностью реализовано

Всего лишь добавлением связок input + label, мы сократили список необходимого функционала с 10 пунктов до 3. Неплохо, но ведь это не конец, верно?

Чтобы реализовать пункт Select.multiple (множественный выбор) — достаточно сделать так:

<form>
  <div class="content">
    <input id="selectName0" type="checkbox" value="0" name="selectName" />
    <label for="selectName0">Описание 0 пункта</label>
    <input id="selectName1" type="checkbox" value="1" name="selectName" />
    <label for="selectName1">Описание 1 пункта</label>
    <input id="selectName2" type="checkbox" value="2" name="selectName" />
    <label for="selectName2">Описание 2 пункта</label>
  </div>
</form>

Мы всего-навсего меняем тип input’ов с Radio на Checkbox, и получаем практически полный аналог multiple.

Разница в том, что для множественного выбора не нужно зажимать ctrl (ну а если кто-то хочет полностью имитировать функционал — JavaScript в помощь).

Что осталось?

  1. Select — disabled, size
  2. Option — полностью реализовано

Ну что ж, и Select.disabled и Select.size предельно просто реализуются с помощью CSS:

  • Select.size — какой зададите размер, такой и будет. Необходимо будет просто добавить контейнер.
  • Select.disabled — для контейнера нужно добавить pointer-events: none, чтобы отменить реакцию на любые действия пользователя (наведение, клики и т.д.), ну и можно сделать его чуть прозрачным.

Итак, основной функционал есть. Чего не хватает?

Нужно также добавить автозаполнение заголовка для выпадающего меню с единственным выбором, а также возникнет проблема при сбросе формы (кнопка Reset), т.к. заголовок не сбросится. Но и это — вполне решаемо (с помощью JavaScript).


А теперь — примеры:

Немного реализации (выпадающее меню с единичным выбором):

И ещё немного (не выпадающее меню с множественным выбором):

Бонус: не знаю, зачем я это сделал, но… выпадающее меню с единичным выбором и работающим на CSS сбросом заголовка:


Зачем это нужно?

В связи с тем, что судя по комментариям, не все понимают, для чего будет полезен данный код, считаю нужным дать некоторые разъяснения.

При стилизации выпадающих списков вида:

<select>
  <option>Пункт 1</option>
  <option>Пункт 2</option>
</select>

есть серьёзные ограничения стилизации. Поэтому их заменяют на простые списки:

<ul>
  <li>Пункт 1</li>
  <li>Пункт 2</li>
</ul>

которым с помощью JavaScript навешивают весь необходимый функционал.

Поскольку изначально списки никак не взаимодействуют с формами, из-за этого возникают проблемы.

Мало того, что необходимо реализовать весь основной функционал:

  • переключение пунктов и их взаимодействие
  • состояния (checked, disabled)
  • привязка к форме и отправка данных на сервер
  • инициализация исходных данных (автозаполнение)
  • сброс формы (при нажатии на кнопку «reset» список нужно вернуть в состояние при инициализации)

Фактически, если в JavaScript что-то ломается, не важно, из-за чего — скрипт не догрузился, возник баг, внесли правки — при возникновении любой проблемы выпадающий список превращается в… что-то, выглядящее как выпадающий список, но не работающее.
Вообще. Никак.

Для пользователя это будет выглядеть так: есть выпадающий список, но работать с ним нельзя.

Для сервера это будет выглядеть ещё «веселее» — пришла форма, в которой не хватает части данных. Хорошо, что такую ситуацию заранее предусмотрели при разработке… Ведь предусмотрели, правда?


Плюсы получившегося решения:

  • Весь основной функционал (смотри выше), кроме сброса заголовка ВСЕГДА будет работать. Даже если у человека вообще отключён JavaScript (хоть это и стало практически неактуально). Единственное, что может пойти не так — нельзя будет открыть список. Но и в этом случае отправится значение по умолчанию, плюс смену состояний — список открыт/закрыт — можно реализовать прямо в коде html (защита от проблем с файлом JS), или вообще открывать по наведению.
  • Данного функционала достаточно для большинства подобных списков. Да, возникнут проблемы у людей, использующих дополнительный функционал (об этом ниже). Но в случае со списком на ulli для работы и вовсе требуется библиотека, и много что может пойти не так.

Минусы (доп. функционал, который не реализован, и добавляется JavaScript’ом / библиотеками):

  • Переключение с помощью tab
  • Управление стрелками (в стандартном select можно менять выбранный пункт кнопками вверх-вниз)
  • Озвучка скринридерами (для людей, у которых проблемы со зрением текст на странице озвучивается)
  • Не работает как нативный select на мобильных (на мобильных select довольно удобно работает сам по себе. При желании можно определять устройство и подменять на стандартный select)
  • Список не умеет выпадать вверх, если снизу край вьюпорта (JS сделает это)
  • Группировка пунктов (аналог OptGroup) (сложно, и очень редко встречается)

Как видно, ничто из вышеперечисленных минусов не является критичным для подавляющего большинства списков, и при необходимости реализуется с помощью JavaScript, а потому…


Добро пожаловать в мир, где Ваши библиотеки для стилизации Select-Option-подобных списков станут чуточку меньше, а работа с этими списками без библиотек — почти комфортной!


UPD: как оказалось, в случае с чекбоксами атрибут required работает некорректно, и его также необходимо эмулировать с помощью JavaScript (на данный момент обязательными становятся все чекбоксы, отмеченные как required, и только они)

Modern CSS gives us a range of properties to achieve custom select styles that have a near-identical initial appearance for single, multiple, and disabled select elements across the top browsers.

A few properties and techniques our solution will use:

  • clip-path to create the custom dropdown arrow
  • CSS grid layout to align the native select and arrow
  • custom CSS variables for flexible styling
  • em units for relative sizing

Now available: my egghead video course Accessible Cross-Browser CSS Form Styling. You’ll learn to take the techniques described in this tutorial to the next level by creating a themable form design system to extend across your projects.

Common Issues with Native Selects

As with all form field types, <select> varies across browsers in its initial appearance.

From left to right, here is the initial appearance for <select> in Firefox, Chrome, and Safari:

initial native select appearance with no custom styling

The differences include box size, font-size, line-height, and most standout is the difference in how the dropdown indicator is styled.

Our goal is to create the same initial appearance across these browsers, inclusive of multiple selects, and disabled states.

Note: The dropdown list is still not stylable, so once the <select> is opened, it will still pick up the individual browser’s styles for the option list. This is ok — we can deal with that to retain the free accessibility of a native select!

Base HTML

We’ll focus on a single <select> to begin.

<label for="standard-select">Standard Select</label>
<div class="select">
<select id="standard-select">
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
<option value="Option 3">Option 3</option>
<option value="Option 4">Option 4</option>
<option value="Option 5">Option 5</option>
<option value="Option length">
Option that has too long of a value to fit
</option>
</select>
</div>

The label is not part of our styling exercise, but its included as a general requirement, notably with the for attribute having the value of the id on the <select>.

To accomplish our custom styles, we’ve wrapped the native select in an extra div with class of select for simplicity in this tutorial.

Reset and Remove Inherited Styles

As is included in all my tutorials as a modern best practice, we add the following reset first:

*,
*::before,
*::after
{
box-sizing: border-box;
}

Following that, we can begin the rule for the native select and apply the following to rest its appearance:

select {
// A reset of styles, including removing the default dropdown arrow
appearance: none;
// Additional resets for further consistency
background-color: transparent;
border: none;
padding: 0 1em 0 0;
margin: 0;
width: 100%;
font-family: inherit;
font-size: inherit;
cursor: inherit;
line-height: inherit;
}

While most of those are likely familiar, the oddball out is appearance. This is an infrequently used property and you’ll note that it is not quite where we’d like it for support, but what it’s primarily providing for us in this instance is the removal of the native browser dropdown arrow.

Note: The CodePen is set up to use autoprefixer which will add required pre-fixed versions of the appearance property. You may need to specifically set this up for your project, or manually add them. My HTML / Sass Jumpstart includes autoprefixer as part of the production build.

The good news is, we can add one more rule to gain removal of the arrow for lower IE versions if you need it:

select::-ms-expand {
display: none;
}

This tip found in the excellent article from Filament Group that shows an alternate method to create select styles.

The last part is to remove the default outline. Don’t worry — we’ll add a replacement later on for the :focus state!

select {
// ...existing styles
outline: none;

And here’s a gif of our progress. You can see there is now zero visual indication that this is a select prior to clicking on it:

demo of interacting with the reset select

Custom Select Box Styles

First, let’s set up some CSS variables. This will allow our select to be flexibly re-colored such as to represent an error state.

:root {
--select-border: #777;
--select-focus: blue;
--select-arrow: var(--select-border);
}

Accessibility note: As a user interface element, the select border must have a 3:1 contrast or greater against the surrounding surface color.

Now it’s time to create the custom select styles which we will apply to the our wrapping div.select:

.select {
width: 100%;
min-width: 15ch;
max-width: 30ch;
border: 1px solid var(--select-border);
border-radius: 0.25em;
padding: 0.25em 0.5em;
font-size: 1.25rem;
cursor: pointer;
line-height: 1.1;
background-color: #fff;
background-image: linear-gradient(to top, #f9f9f9, #fff 33%);
}

First, we set up some width constraints. The min-width and max-width values are mostly for this demo, and you may choose to drop or alter it for your use case.

Then we apply some box model properties, including border, border-radius, and padding. Note the use of the em unit which will keep these properties proportional to the set font-size.

In the reset styles, we set several properties to inherit, so here we define those, including font-size, cursor, and line-height.

Finally, we supply it background properties, including a gradient for the slightest bit of dimension. If you remove the background properties, the select will be transparent and pick up the page background. This may be desirable, however, be aware and test the effects on contrast.

And here’s our progress:
updated select now has a visually apparent box appearance

Custom Select Dropdown Arrow

For our dropdown arrow, we are going to use one of the most exciting modern CSS properties: clip-path.

Clip paths let us make all kind of shapes by «clipping» the otherwise square and rectangle shapes we receive as defaults from most elements. I had fun using clip-path on my recent portfolio site redesign.

Prior to clip-path having better support, alternative methods included:

  • background-image — typically a png, slightly more modern would be an SVG
  • an inline SVG as an additional element
  • the border trick to create a triangle

SVG may feel like the optimal solution, however when used as a background-image it loses the ability to act like an icon in the sense of not being able to alter its properties such as fill color without redefining it entirely. This means we cannot use our CSS custom variable.

Placing an SVG inline solves the fill color issue, however it means including one more element every time a <select> is defined.

With clip-path, we get a crisp, scalable arrow «graphic» that feels like an SVG but with the benefits of being able to use our custom variable and being contained in the style vs. the HTML markup.

To create the arrow, we will define it as an ::after pseudo-element.

.select::after {
content: "";
width: 0.8em;
height: 0.5em;
background-color: var(--select-arrow);
clip-path: polygon(100% 0%, 0 0%, 50% 100%);
}

The clip-path syntax is a little strange, and since it’s not really the focus of this article, I recommend the following resources:

  • Colby Fayock explans the syntax with an example in this egghead video
  • Clippy is an online tool that allows you to select a shape and adjust the points while dynamically generating the clip-path CSS

If you’re following along, you may have noticed the arrow is not appearing despite defining width and height. When inspected, its found that the ::after is not actually being allowed it’s width.

We will resolve this by updating our .select to use CSS grid layout.

.select {
// ...existing styles
display: grid;
}

This lets the arrow appear by essentially extending it a display value akin to «block».

clip-path arrow now appears below the native select

At this stage we can verify that we have indeed created a triangle.

To fix the alignment, we’ll use my favorite CSS grid hack (old hat to you if you’ve read a few articles around here!).

Old CSS solution: position: absolute
New CSS solution: A single grid-template-areas to contain them all

First we’ll define our area, then define that the select and the ::after both use it. The name is scoped to the element its created for, and we’ll keep it easy by calling it «select»:

.select {
// ...existing styles
grid-template-areas: "select";
}

select,
.select:after
{
grid-area: select;
}

Which gives us an overlap of the arrow above the native select due to stacking context via source order:

preview of the updated arrow position above the native select

We can now use grid properties to finalize the alignment of each element:

.select {
// ...existing styles
align-items: center;
}

.select:after {
// ...existing styles
justify-self: end;
}

Ta-da!

finished initial styles for the custom select

:focus State

Oh yeah — remember how we removed the outline? We need to resolve the missing :focus state from dropping that.

There is an upcoming property we could use called :focus-within but it’s still best to include a polyfill for it at this time.

For this tutorial, we’ll use an alternate method that achieves the same result, just a bit heftier.

Unfortunately, this means we need to add one more element into the DOM.

After the native select element, as the last child within .select, add:

<span class="focus"></span>

Why after? Because since this is a pure CSS solution, placing it after the native select means we can alter it when the select is focused by use of the adjacent sibling selector — +.

This allows us to create the following rule:

select:focus + .focus {
position: absolute;
top: -1px;
left: -1px;
right: -1px;
bottom: -1px;
border: 2px solid var(--select-focus);
border-radius: inherit;
}

You may be wondering why we’re back to position: absolute after just learning the previous grid-area hack.

The reason is to avoid recalculating adjustments based on padding. If you try it on your own, you’ll see that even setting width and height to 100% still makes it sit within the padding.

The job position: absolute does best is matching the size of an element. We’re pulling it an extra pixel in each direction to make sure it overlaps the border property.

But, we need to make one more addition to .select to ensure that it’s relative to our select by — well, position: relative.

.select {
// ...existing styles
position: relative;

And here’s our custom select all together as seen in Chrome:

gif demo of focusing and selecting an option in the custom select

Multiple Select

Selects come in a second flavor, which allows a user to select more than one option. From the HTML perspective, this simply means add the multiple attribute, but we’ll also add a class to help create style adjustments called select--multiple:

<label for="multi-select">Multiple Select</label>
<div class="select select--multiple">
<select id="multi-select" multiple>
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
<option value="Option 3">Option 3</option>
<option value="Option 4">Option 4</option>
<option value="Option 5">Option 5</option>
<option value="Option length">
Option that has too long of a value to fit
</option>
</select>
<span class="focus"></span>
</div>

And looking at it, we can see it’s inherited most of our styles favorably, except we don’t need the arrow in this view.

multiple select with inherited styles as previously defined

This is a quick fix to adjust our selector that defines the arrow. We use :not() to exclude our newly defined class:

.select:not(.select--multiple)::after

We have a couple of minor adjustments to make for the multiple select, the first is removing padding that was previously added to make room for the arrow:

select[multiple] {
padding-right: 0;
}

By default, options with a long value will overflow visible area and be clipped, but I found that the main browsers allow the wrapping to be overridden if you desire:

select[multiple] option {
white-space: normal;
}

Optionally, we can set a height on the select to bring a bit more reliable cross-browser behavior. Through testing this, I learned that Chrome and Firefox will show a partial option, but Safari will completely hide an option that is not able to be fully in view.

The height must be set directly on the native select. Given our other styles, the value 6rem will be able to show 3 options:

select[multiple] {
// ...existing styles
height: 6rem;
}

At this point, due to current browser support, we have made as much adjustments as we are able.

The :selected state of the options is fairly customizable in Chrome, somewhat in Firefox, and not at all in Safari. See the CodePen demo for a section that can be uncommented to preview this.

:disabled Styles

While I would advocate for simply not showing disabled controls, we should prepare the styles for that state just to cover our bases.

To emphasis the disabled state, we want to apply a greyed background. But since we’ve set background styles on .select and there isn’t a :parent selector, we need to create one last class to handle for this state:

.select--disabled {
cursor: not-allowed;
background-color: #eee;
background-image: linear-gradient(to top, #ddd, #eee 33%);
}

Here we’ve updated the cursor as an extra hint that the field cannot be interacted with, and updated the background values we previously set to be white to now be more grey for the disabled state.

This results in the following appearances:

previous of the disabled state styles for both single and multiple select

Demo

You can test it for yourself, but here’s a preview of the full solution across (from left) the Firefox, Chrome, and Safari:

final styled selects across the browsers mentioned

By Stephanie Eckles (@5t3ph)

The <select> HTML element represents a control that provides a menu of options.

Try it

The above example shows typical <select> usage. It is given an id attribute to enable it to be associated with a <label> for accessibility purposes, as well as a name attribute to represent the name of the associated data point submitted to the server. Each menu option is defined by an <option> element nested inside the <select>.

Each <option> element should have a value attribute containing the data value to submit to the server when that option is selected. If no value attribute is included, the value defaults to the text contained inside the element. You can include a selected attribute on an <option> element to make it selected by default when the page first loads.

The <select> element has some unique attributes you can use to control it, such as multiple to specify whether multiple options can be selected, and size to specify how many options should be shown at once. It also accepts most of the general form input attributes such as required, disabled, autofocus, etc.

You can further nest <option> elements inside <optgroup> elements to create separate groups of options inside the dropdown.

For further examples, see The native form widgets: Drop-down content.

Attributes

This element includes the global attributes.

autocomplete

A string providing a hint for a user agent’s autocomplete feature. See The HTML autocomplete attribute for a complete list of values and details on how to use autocomplete.

autofocus

This Boolean attribute lets you specify that a form control should have input focus when the page loads. Only one form element in a document can have the autofocus attribute.

disabled

This Boolean attribute indicates that the user cannot interact with the control. If this attribute is not specified, the control inherits its setting from the containing element, for example <fieldset>; if there is no containing element with the disabled attribute set, then the control is enabled.

form

The <form> element to associate the <select> with (its form owner). The value of this attribute must be the id of a <form> in the same document. (If this attribute is not set, the <select> is associated with its ancestor <form> element, if any.)

This attribute lets you associate <select> elements to <form>s anywhere in the document, not just inside a <form>. It can also override an ancestor <form> element.

multiple

This Boolean attribute indicates that multiple options can be selected in the list. If it is not specified, then only one option can be selected at a time. When multiple is specified, most browsers will show a scrolling list box instead of a single line dropdown.

name

This attribute is used to specify the name of the control.

required

A Boolean attribute indicating that an option with a non-empty string value must be selected.

size

If the control is presented as a scrolling list box (e.g. when multiple is specified), this attribute represents the number of rows in the list that should be visible at one time. Browsers are not required to present a select element as a scrolled list box. The default value is 0.

Note: According to the HTML specification, the default value for size should be 1; however, in practice, this has been found to break some websites, and no other browser currently does that, so Mozilla has opted to continue to return 0 for the time being with Firefox.

Usage notes

Selecting multiple options

On a desktop computer, there are a number of ways to select multiple options in a <select> element with a multiple attribute:

Mouse users can hold the Ctrl, Command, or Shift keys (depending on what makes sense for your operating system) and then click multiple options to select/deselect them.

Warning: The mechanism for selecting multiple non-contiguous items via the keyboard described below currently only seems to work in Firefox.

On macOS, the Ctrl + Up and Ctrl + Down shortcuts conflict with the OS default shortcuts for Mission Control and Application windows, so you’ll have to turn these off before it will work.

Keyboard users can select multiple contiguous items by:

  • Focusing on the <select> element (e.g. using
    Tab
    ).
  • Selecting an item at the top or bottom of the range they want to select using the
    Up
    and
    Down
    cursor keys to go up and down the options.
  • Holding down the
    Shift
    key and then using the
    Up
    and
    Down
    cursor keys to increase or decrease the range of items selected.

Keyboard users can select multiple non-contiguous items by:

  • Focusing on the <select> element (e.g. using
    Tab
    ).
  • Holding down the
    Ctrl
    key then using the
    Up
    and
    Down
    cursor keys to change the «focused» select option, i.e. the one that will be selected if you choose to do so. The «focused» select option is highlighted with a dotted outline, in the same way as a keyboard-focused link.
  • Pressing
    Space
    to select/deselect «focused» select options.

Styling with CSS

The <select> element is notoriously difficult to style productively with CSS. You can affect certain aspects like any element — for example, manipulating the box model, the displayed font, etc., and you can use the appearance property to remove the default system appearance.

However, these properties don’t produce a consistent result across browsers, and it is hard to do things like line different types of form element up with one another in a column. The <select> element’s internal structure is complex, and hard to control. If you want to get full control, you should consider using a library with good facilities for styling form widgets, or try rolling your own dropdown menu using non-semantic elements, JavaScript, and WAI-ARIA to provide semantics.

For more useful information on styling <select>, see:

  • Styling HTML forms
  • Advanced styling for HTML forms

Also see the «Customizing select styles» example below for an example of you could attempt a simple <select> styling.

Examples

Basic select

The following example creates a very simple dropdown menu, the second option of which is selected by default.

<!-- The second value will be selected initially -->
<select name="choice">
  <option value="first">First Value</option>
  <option value="second" selected>Second Value</option>
  <option value="third">Third Value</option>
</select>

Advanced select with multiple features

The follow example is more complex, showing off more features you can use on a <select> element:

<label>Please choose one or more pets:
  <select name="pets" multiple size="4">
    <optgroup label="4-legged pets">
      <option value="dog">Dog</option>
      <option value="cat">Cat</option>
      <option value="hamster" disabled>Hamster</option>
    </optgroup>
    <optgroup label="Flying pets">
      <option value="parrot">Parrot</option>
      <option value="macaw">Macaw</option>
      <option value="albatross">Albatross</option>
    </optgroup>
  </select>
</label>

You’ll see that:

  • Multiple options are selectable because we’ve included the multiple attribute.
  • The size attribute causes only 4 lines to display at a time; you can scroll to view all the options.
  • We’ve included <optgroup> elements to divide the options up into different groups. This is a purely visual grouping, its visualization generally consists of the group name being bolded, and the options being indented.
  • The «Hamster» option includes a disabled attribute and therefore can’t be selected at all.

Customizing select styles

This example shows how you could use some CSS and JavaScript to provide extensive custom styling for a <select> box.

This example basically:

  • Clones the <select>‘s context (the <option>s) in a parent wrapper and reimplements the standard expected behavior using additional HTML elements and JavaScript. This includes basic tab behavior to provide keyboard accessibility.
  • Maps some standards native attributes to data-attributes of the new elements in order to manage state and CSS.

Note: Not all native features are supported, it’s a Proof of Concept. IT starts from standard HTML but the same results can be achieved starting from JSON data, custom HTML, or other solutions.

HTML

<form>
  <fieldset>
    <legend>Standard controls</legend>
    <select name="1A" id="select" autocomplete="off" required>
      <option>Carrots</option>
      <option>Peas</option>
      <option>Beans</option>
      <option>Pneumonoultramicroscopicsilicovolcanoconiosis</option>
    </select>
  </fieldset>
  <fieldset id="custom">
    <legend>Custom controls</legend>
    <select name="2A" id="select" autocomplete="off" required>
      <option>Carrots</option>
      <option>Peas</option>
      <option>Beans</option>
      <option>Pneumonoultramicroscopicsilicovolcanoconiosis</option>
    </select>
  </fieldset>
</form>

CSS

body {
  font-family: Cambria, Cochin, Georgia, Times, "Times New Roman", serif;
}

.select:focus {
  border-color: blue;
}

html body form fieldset#custom div.select[data-multiple] div.header {
  display: none;
}

html body form fieldset#custom div.select div.header {
  content: "↓";
  display: flex;
  flex: 1;
  align-items: center;
  padding: 0;
  position: relative;
  width: auto;
  box-sizing: border-box;
  border-width: 1px;
  border-style: inherit;
  border-color: inherit;
  border-radius: inherit;
}

html body form fieldset#custom div.select div.header::after {
  content: "↓";
  align-self: stretch;
  display: flex;
  align-content: center;
  justify-content: center;
  justify-items: center;
  align-items: center;
  padding: 0.5em;
}

html body form fieldset#custom div.select div.header:hover::after {
  background-color: blue;
}

.select .header select {
  appearance: none;
  font-family: inherit;
  font-size: inherit;
  padding: 0;
  border-width: 0;
  width: 100%;
  flex: 1;
  display: none;
}

.select .header select optgroup {
  display: none;
}

.select select div.option {
  display: none;
}

html body form fieldset#custom div.select {
  user-select: none;
  box-sizing: border-box;
  position: relative;
  border-radius: 4px;
  border-style: solid;
  border-width: 0;
  border-color: gray;
  width: auto;
  display: inline-block;
}

html body form fieldset#custom div.select:focus,
html body form fieldset#custom div.select:hover {
  border-color: blue;
}

html body form fieldset#custom div.select[data-open] {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

html body form fieldset#custom div.select[data-open] datalist {
  display: initial;
}

html body form fieldset#custom div.select datalist {
  appearance: none;
  position: absolute;
  border-style: solid;
  border-width: 1px;
  border-color: gray;
  left: 0;
  display: none;
  width: 100%;
  box-sizing: border-box;
  z-index: 2;
  border-bottom-left-radius: 4px;
  border-bottom-right-radius: 4px;
}

html body form fieldset#custom div.select datalist div.option {
  background-color: white;
  margin-bottom: 1px;
  cursor: pointer;
  padding: 0.5em;
  border-width: 0;
}

html body form fieldset#custom div.select datalist div.option:hover,
html body form fieldset#custom div.select datalist div.option:focus,
html body form fieldset#custom div.select datalist div.option:checked {
  background-color: blue;
  color: white;
}

html
  body
  form
  fieldset#custom
  div.select
  div.optgroup
  div.option[data-disabled] {
  color: gray;
}

html
  body
  form
  fieldset#custom
  div.select
  div.optgroup
  div.option[data-checked] {
  background-color: blue;
  color: white;
}

html body form fieldset#custom div.select div.optgroup div.label {
  font-weight: bold;
}

html body form fieldset#custom div.select div.optgroup div.option div.label {
  font-weight: normal;
  padding: 0.25em;
}

html body form fieldset#custom div.select div.header span {
  flex: 1;
  padding: 0.5em;
}

JavaScript

const selects = custom.querySelectorAll('select');
for (const select of selects) {
  const div = document.createElement('div');
  const header = document.createElement('div');
  const datalist = document.createElement('datalist');
  const optgroups = select.querySelectorAll('optgroup');
  const span = document.createElement('span');
  const options = select.options;
  const parent = select.parentElement;
  const multiple = select.hasAttribute('multiple');
  function onclick(e) {
    const disabled = this.hasAttribute('data-disabled');
    select.value = this.dataset.value;
    span.innerText = this.dataset.label;
    if (disabled) return;
    if (multiple) {
      if (e.shiftKey) {
        const checked = this.hasAttribute("data-checked");
        if (checked) {
          this.removeAttribute("data-checked");
        } else {
          this.setAttribute("data-checked", "");
        }
      } else {
        const options = div.querySelectorAll('.option');
        for (let i = 0; i < options.length; i++) {
          const option = options[i];
          option.removeAttribute("data-checked");
        }
        this.setAttribute("data-checked", "");
      }
    }
  }

  function onkeyup(e) {
    e.preventDefault();
    e.stopPropagation();
    if (e.keyCode === 13) {
      this.click();
    }
  }

  div.classList.add('select');
  header.classList.add('header');
  div.tabIndex = 1;
  select.tabIndex = -1;
  span.innerText = select.label;
  header.appendChild(span);

  for (const attribute of select.attributes) {
    div.dataset[attribute.name] = attribute.value;
  }
  for (let i = 0; i < options.length; i++) {
    const option = document.createElement('div');
    const label = document.createElement('div');
    const o = options[i];
    for (const attribute of o.attributes) {
      option.dataset[attribute.name] = attribute.value;
    }
    option.classList.add('option');
    label.classList.add('label');
    label.innerText = o.label;
    option.dataset.value = o.value;
    option.dataset.label = o.label;
    option.onclick = onclick;
    option.onkeyup = onkeyup;
    option.tabIndex = i + 1;
    option.appendChild(label);
    datalist.appendChild(option);
  }
  div.appendChild(header);
  for (const o of optgroups) {
    const optgroup = document.createElement('div');
    const label = document.createElement('div');
    const options = o.querySelectorAll('option');

    Object.assign(optgroup, o);
    optgroup.classList.add('optgroup');
    label.classList.add('label');
    label.innerText = o.label;
    optgroup.appendChild(label);
    div.appendChild(optgroup);
    for (const o of options) {
      const option = document.createElement('div');
      const label = document.createElement('div');

      for (const attribute of o.attributes) {
        option.dataset[attribute.name] = attribute.value;
      }
      option.classList.add('option');
      label.classList.add('label');
      label.innerText = o.label;
      option.tabIndex = i + 1;
      option.dataset.value = o.value;
      option.dataset.label = o.label;
      option.onclick = onclick;
      option.onkeyup = onkeyup;
      option.tabIndex = i + 1;
      option.appendChild(label);
      optgroup.appendChild(option);
    }
  }

  div.onclick = (e) => {
    e.preventDefault();
  };

  parent.insertBefore(div, select);
  header.appendChild(select);
  div.appendChild(datalist);
  datalist.style.top = `${header.offsetTop + header.offsetHeight}px`;

  div.onclick = (e) => {
    if (!multiple) {
      const open = this.hasAttribute("data-open");
      e.stopPropagation();
      if (open) {
        div.removeAttribute("data-open");
      } else {
        div.setAttribute("data-open", "");
      }
    }
  };

  div.onkeyup = (event) => {
    event.preventDefault();
    if (event.keyCode === 13) {
      div.click();
    }
  };

  document.addEventListener('click', (e) => {
    if (div.hasAttribute("data-open")) {
      div.removeAttribute("data-open");
    }
  });

  const width = Math.max(...Array.from(options).map((e) => {
    span.innerText = e.label;
    return div.offsetWidth;
  }));

  console.log(width);
  div.style.width = `${width}px`;
}
document.forms[0].onsubmit = (e) => {
  const data = new FormData(this);
  e.preventDefault();
  submit.innerText = JSON.stringify([...data.entries()]);
};

Result

Technical summary

Content categories Flow content,
phrasing content,
interactive content,
listed,
labelable,
resettable, and
submittable
form-associated element
Permitted content Zero or more <option> or
<optgroup> elements.
Tag omission None, both the starting and ending tag are mandatory.
Permitted parents Any element that accepts
phrasing content.
Implicit ARIA role combobox with no
multiple attribute and no
size attribute greater than 1, otherwise
listbox
Permitted ARIA roles menu with no
multiple attribute and no
size attribute greater than 1, otherwise no
role permitted
DOM interface HTMLSelectElement

Specifications

Specification
HTML Standard
# the-select-element

Browser compatibility

BCD tables only load in the browser

See also

  • Events fired by <select>: change, input
  • The <option> element
  • The <optgroup> element

Когда-то было довольно сложно оформить элемент <select> для всех браузеров.

Чтобы избежать недостатков, которые были раньше, используйте оформление родительского элемента, добавление псевдоэлементов, а также применение JavaScript.

Оказывается, значительная часть стилей могут создать постоянный и приемлемый блок выбора (selection box) в новых браузерах, лучшим способом сохраняясь в старых браузерах.

Есть множество элементов в блоке выбора, к которым можно применить стиль, в частности width, height, font, border, color, padding, box-shadow и background color.

Рассмотрим пример, где применен стиль:

Пример

<!DOCTYPE html>
<html>
  <head>
    <title>Заголовок документа</title>
    <style>
      .box {
      width: 120px;
      height: 30px;
      border: 1px solid #999;
      font-size: 18px;
      color: #1c87c9;
      background-color: #eee;
      border-radius: 5px;
      box-shadow: 4px 4px #ccc;
      }
    </style>
  </head>
  <body>
    <p>Обычный блок выбора:</p>
    <select>
      <option>Кофе</option>
      <option>Чай</option>
      <option>Вода</option>
      <option selected>Коктейль</option>
    </select>
    <p>Оформленный блок выбора:</p>
    <select class="box">
      <option>Кофе</option>
      <option>Чай</option>
      <option>Вода</option>
      <option selected>Коктейль</option>
    </select>
  </body>
</html>

Но стрелка выпадающего (раскрывающегося) списка не меняется. Нет никакого непосредственного способа для ее оформления, но существуют некоторые методы, которые могут быть использованы для изменения стрелки раскрывающегося списка по умолчанию. Давайте рассмотрим эти 3 метода ниже.

Чтобы скрыть стрелку по умолчанию раскрывающегося списка <select>, установите CSS свойство appearance в значение «none», и дальше добавьте выбранную вами стрелку с помощью сокращенного свойства background.

Заметьте, что свойство appearance все еще считается экспериментальным, и вам потребуется использовать префикс -moz- (для Firefox) и -webkit- (для Chrome, Safari, Opera) для максимальной совместимости браузера.

Пример

<!DOCTYPE html>
<html>
  <head>
    <title>Заголовок документа</title>
    <style>
      select {
      width: 140px;
      height: 35px;
      padding: 5px 35px 5px 5px;
      font-size: 18px;
      border: 2px solid #ccc;
      -webkit-appearance: none;
      -moz-appearance: none;
      appearance: none;
      background: url("/uploads/media/default/0001/02/f7b4d3d2ba3fe1d8518e6e63d7740e1e73921abf.png") 96% / 15% no-repeat #eee;
      }
      select::-ms-expand { 
      display: none; /* удалите стрелку по умолчанию в IE 10 и 11 */
      }
    </style>
  </head>
  <body>
    <select>
      <option>Кофе</option>
      <option>Чай</option>
      <option>Вода</option>
      <option selected>Коктейль</option>
    </select>
  </body>
</html>

Сначала вставьте элемент <select>
в div контейнер с фиксированной шириной и установите overflow: hidden. Потом для элемента <select> задайте ширину на 20px больше, чем элемент <div>. Таким образом, стрелка раскрывающегося списка будет скрыта (так как для контейнера установлено overflow: hidden), и теперь уже можно будет применить фоновое изображение с правой стороны <div>.

Можно использовать этот метод, так как все браузеры эффективно поддерживают overflow: hidden.

Заметьте, что недостатком этого метода является то, что опции визуально длиннее, чем меню выбора.

Пример

<!DOCTYPE html>
<html>
  <head>
    <title>Заголовок документа</title>
    <style>
      .mystyle select {
      background: transparent;
      width: 140px;
      height: 35px;
      border: 1px solid #ccc;
      font-size: 18px;
      } 
      .mystyle {
      width: 120px;
      height: 34px;
      border: 1px solid #111;
      border-radius: 3px;
      overflow: hidden;
      background: url("/uploads/media/default/0001/02/f7b4d3d2ba3fe1d8518e6e63d7740e1e73921abf.png") 96% / 20% no-repeat #ddd;
      }
    </style>
  </head>
  <body>
    <div class="mystyle">
      <select>
        <option>Кофе</option>
        <option>Чай</option>
        <option>Вода</option>
        <option selected>Коктейль</option>
      </select>
    </div>
  </body>
</html>

CSS свойство pointer-events может быть использовано для создания индивидуальных раскрывающихся списков <select>.

Этот метод работает отлично и хорошо поддерживается браузерами.

Пример

<!DOCTYPE html>
<html>
  <head>
    <title>Заголовок документа</title>
    <style>
      .mybox {
      position: relative;
      display: inline-block;
      }
      select {
      display: inline-block;
      height: 30px;
      width: 150px;
      outline: none;
      color: #74646e;
      border: 1px solid #ccc;
      border-radius: 5px;
      box-shadow: 1px 1px 2px #999;
      background: #eee;
      }
      /* Select arrow styling */
      .mybox .myarrow{
      width: 23px;
      height: 28px;
      position: absolute;
      display: inline-block;
      top: 1px;
      right: 3px;
      background: url("/uploads/media/default/0001/02/f7b4d3d2ba3fe1d8518e6e63d7740e1e73921abf.png") right / 90% no-repeat #eee;
      pointer-events: none;
      }
    </style>
  </head>
  <body>
    <div class="mybox">
      <span class="myarrow"></span>
      <select>
        <option>Кофе</option>
        <option>Чай</option>
        <option>Вода</option>
        <option selected>Коктейль</option>
      </select>
    </div>
  </body>
</html>

4) Используйте знаки препинания вместо стрелок раскрывающегося списка

Отличным методом является использование предпочитаемых вами знаков вместо стандартного знака для блока <select>.

Установите знаки с помощью свойства content и установите соответствующий font. Здесь можно установить «Consolas» и «monospace». Потом поверните знак пунктуации, используя свойство transform.

Здесь блок <select> находится внутри элемента <label>. Таким образом, мы сможем установить для него курсор, даже если свойство pointer-events установлено в «none».

Пример

<!DOCTYPE html>
<html>
  <head>
    <title>Заголовок документа</title>
    <style>
      select {
      width: 140px;
      height: 35px;
      padding: 4px;
      border-radius:4px;
      box-shadow: 2px 2px 8px #999;
      background: #eee;
      border: none;
      outline: none;
      display: inline-block;
      -webkit-appearance:none;
      -moz-appearance: none;
      appearance: none;
      cursor: pointer;
      }
      label {
      position: relative;
      }
      label:after {
      content:'<>';
      font: 11px "Consolas", monospace;
      color: #666;
      -webkit-transform: rotate(90deg);
      -moz-transform: rotate(90deg);
      -ms-transform: rotate(90deg);
      transform: rotate(90deg);
      right: 8px; 
      top:2px;
      padding: 0 0 2px;
      border-bottom: 1px solid #ddd;
      position: absolute;
      pointer-events: none;
      }
      label:before {
      content: '';
      right: 6px; 
      top:0px;
      width: 20px; 
      height: 20px;
      background: #eee;
      position: absolute;
      pointer-events: none;
      display: block;
      }
    </style>
  </head>
  <body>
    <label>
      <select>
        <option>Кофе</option>
        <option>Чай</option>
        <option>Вода</option>
        <option selected>Коктейль</option>
      </select>
    </label>
  </body>
</html>

HTML CSS JS

Стилизация select

Дата размещения статьи 17/11/2018 👁20641

Стилизация select

Стилизация select на чистом CSS без использования сторонних библиотек или JavaScript кода. А также бонус: рассмотрим как стилизовать select option при помощи JavaScript и jQuery.

  1. Стилизация slect при помощи appearance.
  2. Стилизация select option.
  3. Создание выпадающего списка, используя input.
  4. Проверка, открыт ли select.

Стилизация select

Структура будет стандартной:

<select size="1">
    <option>Слон</option>
    <option>Бегемот</option>
    <option>Жираф</option>
</select>

Чтобы в select отображаемая строка была одна используем атрибут size со значением 1.

Стилизация для нашего select.

-webkit-appearance: none;
-moz-appearance: none;
-ms-appearance: none;
appearance: none;
background: url("path/img.png") no-repeat right center;
outline: 0;

Получим ↓

В примере выше мы прописали четыре строчки ccs свойства appearance с вендорными префиксами, чтобы свойство работало одинаково во всех браузерах. Что это за свойство читайте ниже.

Вся сложность заключалась лишь в замене стандартной стрелки в прямоугольнике, вместо которой мы реализовали background. Таким образом можно вставить любую картинку. Необходимо лишь подогнать размер при помощи свойства background-size

Appearance CSS

Реализовать нашу задачу помогло css3 свойство appearance.

Данное свойство позволяет изменить вид элемента на: button, checkbox, radio, field, icon и многое другое. В нашем случае мы вообще скрыли элемент, используя none и добавили картинку с помощью background.

Стилизация select option

Для того чтобы стилизовать select option нам потребуется JavaScript. Начнём с HTML и CSS.

<select class="select" name="language">
    <option disabled>Выбрать</option>
    <option value="HTML">HTML</option>
    <option value="JavaScript">JavaScript</option>
    <option value="PHP">PHP</option>
</select>
.select {
    display: block;
    max-width: 215px;
    width: 100%;
    position: relative;
}
.new-select {
    position: relative;
    border: 1px solid #ced4da;
    padding: 10px 15px;
    cursor: pointer;
    user-select: none;
}
.new-select__list {
    position: absolute;
    top: 45px;
    left: 0;
    border: 1px solid #ced4da;
    cursor: pointer;
    width: 100%;
    z-index: 2;
    background: #fff;
    user-select: none;
}
.new-select__list.on {
    display: block;
}
.new-select__item span {
    display: block;
    padding: 10px 15px;
}
.new-select__item span:hover {
    color: #12b223;
}
.new-select:after {
    content: "";
    display: block;
    width: 25px;
    height: 25px;
    position: absolute;
    right: 9px;
    top: 9px;
    background: url("path-to-image") no-repeat right center / cover;
    opacity: 0.6;
    transition: all .27s ease-in-out;
    transform: rotate(0deg);
}
.new-select.on:after {
    transform: rotate(180deg);
}

Перед JavaScript-кодом должен быть подключен jQuery.

$(".select").each(function () {
    const _this = $(this),
        selectOption = _this.find("option"),
        selectOptionLength = selectOption.length,
        selectedOption = selectOption.filter(":selected"),
        duration = 450; // длительность анимации

    _this.hide();
    _this.wrap("<div class='select'></div>");
    $("<div>", {
        class: "new-select",
        text: _this.children("option:disabled").text()
    }).insertAfter(_this);

    const selectHead = _this.next(".new-select");
    $("<div>", {
        class: "new-select__list"
    }).insertAfter(selectHead);

    const selectList = selectHead.next(".new-select__list");
    for (let i = 1; i < selectOptionLength; i++) {
        $("<div>", {
            class: "new-select__item",
            html: $("<span>", {
                text: selectOption.eq(i).text()
            })
        })
            .attr("data-value", selectOption.eq(i).val())
            .appendTo(selectList);
    }

    const selectItem = selectList.find(".new-select__item");
    selectList.slideUp(0);
    selectHead.on("click", function () {
        if (!$(this).hasClass("on")) {
            $(this).addClass("on");
            selectList.slideDown(duration);

            selectItem.on("click", function () {
                let chooseItem = $(this).data("value");

                $("select").val(chooseItem).attr("selected", "selected");
                selectHead.text($(this).find("span").text());

                selectList.slideUp(duration);
                selectHead.removeClass("on");
            });

        } else {
            $(this).removeClass("on");
            selectList.slideUp(duration);
        }
    });
});

Input select

Более простой вариант при помощи input. Данный вариант мне нравится больше.

<div class="select">
    <input class="select__input" type="hidden" name="">
    <div class="select__head">Выберите</div>
    <ul class="select__list" style="display: none;">
        <li class="select__item">Стилизация select CSS</li>
        <li class="select__item">Стилизация select JavaScript</li>
        <li class="select__item">Стилизация select, используя input</li>
    </ul>
</div>

Стили.

.select {
    position: relative;
    display: block;
    min-width: 220px;
    width: 100%;
    max-width: 400px;
    margin-bottom: 20px;
}
.select__head {
    width: 100%;
    max-width: 100%;
    box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
    border-radius: 10px;
    padding: 14px 15px;
    font-size: 14px;
    line-height: 18px;
    color: rgba(66, 67, 72, 0.8);
    cursor: pointer;
}
.select__head::after {
    width: 10px;
    height: 6px;
    background: #FFF url('data:image/svg+xml,%3Csvg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http: //www.w3.org/2000/svg"%3E%3Cpath fill-rule="evenodd" clip-rule="evenodd" d="M4.50495 5.78413L0.205241 1.25827C-0.0684138 0.970375 -0.0684138 0.503596 0.205241 0.215836C0.478652 -0.0719461 0.922098 -0.071946 1.19549 0.215837L5.00007 4.22052L8.80452 0.215953C9.07805 -0.0718292 9.52145 -0.0718292 9.79486 0.215953C10.0684 0.503736 10.0684 0.970492 9.79486 1.25839L5.49508 5.78425C5.35831 5.92814 5.17925 6 5.00009 6C4.82085 6 4.64165 5.928 4.50495 5.78413Z" fill="%23ED266A"/%3E%3C/svg%3E%0A') no-repeat center / cover;
    position: absolute;
    right: 20px;
    bottom: 50%;
    transform: translateY(50%);
    content: "";
    display: block;
    transition: .2s ease-in;
}
.select__head.open::after {
    transform: translateY(50%) rotate(180deg);
}
.select__list {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: #fff;
    box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
    border-radius: 10px;
    margin-top: 5px;
    max-height: 205px;
    overflow-x: hidden;
    overflow-y: auto;
    z-index: 100;
    margin: 0;
    padding: 0;
    font-size: 14px;
    color: #424348;
    scrollbar-color: dark;
    scrollbar-width: thin;
    overscroll-behavior: contain;
}
.select__list::-webkit-scrollbar {
    width: 7px;
    background-color: #F8F9FA;
    padding: 5px;
}
.select__list::-webkit-scrollbar-thumb {
    border-radius: 10px;
    background-color: #D9D9D9;
}
.select__list .select__item {
    position: relative;
    border-top: 1px solid rgba(224, 229, 231, 0.5);
    padding: 10px 15px;
    cursor: pointer;
    list-style-type: none;
}
.select__list .select__item:hover {
    background-color: rgba(224, 229, 231, 0.5);
}

jQuery код.

jQuery(($) => {
    $(".select").on("click", ".select__head", function () {
        if ($(this).hasClass("open")) {
            $(this).removeClass("open");
            $(this).next().fadeOut();
        } else {
            $(".select__head").removeClass("open");
            $(".select__list").fadeOut();
            $(this).addClass("open");
            $(this).next().fadeIn();
        }
    });

    $(".select").on("click", ".select__item", function () {
        $(".select__head").removeClass("open");
        $(this).parent().fadeOut();
        $(this).parent().prev().text($(this).text());
        $(this).parent().prev().prev().val($(this).text());
    });

    $(document).click(function (e) {
        if (!$(e.target).closest(".select").length) {
            $(".select__head").removeClass("open");
            $(".select__list").fadeOut();
        }
    });
});

Проверка открыт ли select

Будем изменять положение стрелки в зависимости от того открыт или закрыт select.

const select = document.querySelector("select");

select.addEventListener("blur", () => selectEvent());
select.addEventListener("click", () => selectEvent());

selectEvent = (event) => {
    if (event.type == "click") {
        if (select.classList.contains("change")) {
            select.classList.remove("change");
        } else {
            select.classList.add("change");
        }
    }
    if (event.type == "blur") {
        select.classList.remove("change");
    }
};

Если вам понравилась статья про стилизацию select, рекомендую прочитать про Стилизацию чекбоксов.

Дата обновления статьи 08/05/2022 05:44

Как изменить маркер списка Настройка Photoshop для верстки

Надеюсь, вам понравилась данная информация. Если вам интересна тема web-разработки,
то можете следить за выходом новых статей в Telegram.

  • JavaScript: Работа с Массивами
  • Наличие Динамически Добавленного Элемента
  • Стилизация Input File
  • Предзагрузка Картинок — Предварительная Загрузка Изображений на JavaScript
  • Стилизация Скролла
  • События Формы

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Как изменить стиль radiobutton
  • Как изменить стиль radio css
  • Как изменить стиль python
  • Как изменить стиль pycharm
  • Как изменить стиль placeholder css

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии