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

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

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

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

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

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

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

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

единицы 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;
}

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

Пользовательские стили элементов 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

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

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