Создание компонента кнопки

Базовый обзор того, как создавать адаптивные к цвету, отзывчивые и доступные компоненты <button> .

В этом посте я хочу поделиться своими мыслями о том, как создать адаптивный к цвету, отзывчивый и доступный элемент <button> . Попробуйте демо и просмотрите исходный код

Взаимодействие с кнопками осуществляется с помощью клавиатуры и мыши в светлой и темной темах.

Если вы предпочитаете видео, вот версия этого поста на YouTube:

Обзор

Поддержка браузера

  • Хром: 1.
  • Край: 12.
  • Фаерфокс: 1.
  • Сафари: 1.

Источник

Элемент <button> создан для взаимодействия с пользователем. Событие click срабатывает при нажатии клавиатуры, мыши, прикосновении, голосе и т. д., с умными правилами относительно его времени . Он также поставляется с некоторыми стилями по умолчанию в каждом браузере, поэтому вы можете использовать их напрямую без какой-либо настройки. Используйте color-scheme , чтобы выбрать светлые и темные кнопки браузера.

Существуют также различные типы кнопок , каждая из которых показана на предыдущей вставке Codepen. <button> без типа адаптируется к нахождению внутри <form> , меняясь на тип submit.

<!-- buttons -->
<button></button>
<button type="submit"></button>
<button type="button"></button>
<button type="reset"></button>

<!-- button state -->
<button disabled></button>

<!-- input buttons -->
<input type="button" />
<input type="file">

В конкурсе GUI Challenge в этом месяце каждая кнопка получит стили, помогающие визуально различать их назначение. Кнопки сброса будут иметь предупреждающие цвета, поскольку они разрушительны, а кнопки отправки будут выделены синим текстом, поэтому они будут выглядеть немного более рекламными, чем обычные кнопки.

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

Кнопки также имеют псевдоклассы для CSS, которые можно использовать для стилизации. Эти классы предоставляют CSS-хуки для настройки ощущения от кнопки: :hover , когда мышь находится над кнопкой, :active , когда нажимается мышь или клавиатура, и :focus или :focus-visible для помощи в стилизации вспомогательных технологий.

button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
Предварительный просмотр окончательного набора всех типов кнопок в темной теме.
Предварительный просмотр окончательного набора всех типов кнопок в темной теме

Разметка

В дополнение к типам кнопок, предусмотренным спецификацией HTML, я добавил кнопку со значком и кнопку с пользовательским классом btn-custom .

<button>Default</button>
<input type="button" value="
<input>"/>
<button>
 
<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
   
<path d="..." />
 
</svg>
  Icon
</button>
<button type="submit">Submit</button>
<button type="button">Type Button</button>
<button type="reset">Reset</button>
<button disabled>Disabled</button>
<button class="btn-custom">Custom</button>
<input type="file">

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

<form>
 
<button>Default</button>
  <input type="button" value="
<input>"/>
 
<button>Icon <span data-icon="cloud"></span></button>
 
<button type="submit">Submit</button>
 
<button type="button">Type Button</button>
 
<button type="reset">Reset</button>
 
<button disabled>Disabled</button>
 
<button class="btn-custom btn-large" type="button">Large Custom</button>
 
<input type="file">
</form>

На данный момент матрица комбинаций довольно обширна. Существует более 20 комбинаций кнопок между типами кнопок, псевдоклассами и нахождением в форме или вне формы. Хорошо, что CSS может помочь нам четко сформулировать каждый из них!

Доступность

Кнопочные элементы естественно доступны, но есть несколько общих улучшений.

Наведите курсор и сфокусируйтесь вместе

Мне нравится группировать :hover и :focus вместе с функциональным псевдоселектором :is() . Это помогает гарантировать, что мои интерфейсы всегда учитывают стили клавиатуры и вспомогательных технологий.

button:is(:hover, :focus) {
 

}
Попробуйте демо !

Интерактивное кольцо фокусировки.

Мне нравится анимировать кольцо фокусировки для пользователей клавиатуры и вспомогательных технологий. Я добиваюсь этого, анимируя контур на расстоянии 5 пикселей от кнопки, но только тогда, когда кнопка не активна. Это создает эффект, заставляющий кольцо фокусировки сжиматься до размера кнопки при нажатии.

:where(button, input):where(:not(:active)):focus-visible {
 
outline-offset: 5px;
}

Обеспечение передачи цветового контраста

Существует как минимум четыре различных цветовых сочетания светлого и темного цвета, которые требуют учета цветового контраста: кнопка, кнопка отправки, кнопка сброса и отключенная кнопка. VisBug используется здесь для проверки и отображения всех результатов одновременно:

Скрытие значков от людей, которые не видят

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

<button>
 
<svgaria-hidden="true">...</svg>
  Icon Button
</button>
Chrome DevTools показывает дерево доступности кнопки. Дерево игнорирует изображение кнопки, поскольку для параметра aria-hidden установлено значение true.
Chrome DevTools показывает дерево доступности кнопки. Дерево игнорирует изображение кнопки, поскольку для него установлено значение true.

Стили

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

Адаптивная стратегия настраиваемых свойств

Стратегия пользовательских свойств, используемая в этом вызове GUI, очень похожа на ту, которая используется при построении цветовой схемы . Для адаптивной системы светлых и темных цветов для каждой темы определяется пользовательское свойство, которому присваивается соответствующее имя. Затем используется одно настраиваемое свойство для хранения текущего значения темы и присваивается свойству CSS. Позже одно настраиваемое свойство можно обновить до другого значения, а затем обновить стиль кнопки.

button {
 
--_bg-light: white;
 
--_bg-dark: black;
 
--_bg: var(--_bg-light);

 
background-color: var(--_bg);
}

@media (prefers-color-scheme: dark) {
  button
{
   
--_bg: var(--_bg-dark);
 
}
}

Что мне нравится, так это то, что светлые и темные темы декларативны и ясны. Косвенность и абстракция выгружаются в пользовательское свойство --_bg , которое теперь является единственным «реактивным» свойством; --_bg-light и --_bg-dark являются статическими. Также ясно, что светлая тема является темой по умолчанию, а темная применяется только условно.

Подготовка к единообразию дизайна

Общий селектор

Следующий селектор используется для выбора всех типов кнопок и поначалу кажется немного сложным. :where() используется, поэтому настройка кнопки не требует каких-либо особенностей. Кнопки часто адаптируются для альтернативных сценариев, а селектор :where() упрощает задачу. Внутри :where() выбирается каждый тип кнопки, включая кнопку ::file-selector-button , которую нельзя использовать внутри :is() или :where() .

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"],
  input
[type="file"]
),
:where(input[type="file"])::file-selector-button {
 

}

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

Акцентный цвет кнопки

Кнопки и значки отправки — отличное место для ярких цветов:

--_accent-light: hsl(210 100% 40%);
--_accent-dark: hsl(210 50% 70%);
--_accent: var(--_accent-light);

Цвет текста кнопки

Цвета текста кнопок не белые и не черные, это затемненные или осветленные версии --_accent с использованием hsl() и придерживающиеся оттенка 210 :

--_text-light: hsl(210 10% 30%);
--_text-dark: hsl(210 5% 95%);
--_text: var(--_text-light);

Цвет фона кнопки

Фон кнопок соответствует тому же шаблону hsl() за исключением кнопок светлой темы — они окрашены в белый цвет, поэтому на их поверхности они отображаются близко к пользователю или перед другими поверхностями:

--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);

Фон кнопки хорошо

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

--_input-well-light: hsl(210 16% 87%);
--_input-well-dark: hsl(204 10% 10%);
--_input-well: var(--_input-well-light);

Заполнение кнопок

Расстояние вокруг текста в кнопке определяется с помощью единицы ch — относительной длины к размеру шрифта. Это становится критически важным, когда большие кнопки могут просто пропорционально увеличивать font-size и масштаб кнопок:

--_padding-inline: 1.75ch;
--_padding-block: .75ch;

Граница кнопки

Радиус границы кнопки сохраняется в пользовательском свойстве, поэтому входные данные файла могут соответствовать другим кнопкам. Цвета границ соответствуют установленной адаптивной цветовой системе:

--_border-radius: .5ch;

--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);

Эффект выделения кнопки при наведении

Эти свойства устанавливают свойство размера для перехода при взаимодействии, а цвет выделения соответствует адаптивной цветовой системе. Мы расскажем, как они взаимодействуют позже в этом посте, но в конечном итоге они используются для эффекта box-shadow :

--_highlight-size: 0;

--_highlight-light: hsl(210 10% 71% / 25%);
--_highlight-dark: hsl(210 10% 5% / 25%);
--_highlight: var(--_highlight-light);

Тень текста кнопки

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

--_ink-shadow-light: 0 1px 0 var(--_border-light);
--_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%);
--_ink-shadow: var(--_ink-shadow-light);

Значок кнопки

Значки имеют размер в два символа благодаря единице относительной длины ch , что помогает масштабировать значок пропорционально тексту кнопки. Цвет значка основан на --_accent-color для адаптивного цвета внутри темы.

--_icon-size: 2ch;
--_icon-color: var(--_accent);

Тень кнопки

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

--_shadow-color-light: 220 3% 15%;
--_shadow-color-dark: 220 40% 2%;
--_shadow-color: var(--_shadow-color-light);

--_shadow-strength-light: 1%;
--_shadow-strength-dark: 25%;
--_shadow-strength: var(--_shadow-strength-light);

С помощью адаптивных цветов и интенсивности я могу собрать тени двух глубин:

--_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%));

--_shadow-2:
 
0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)),
 
0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%));

Кроме того, чтобы придать кнопкам немного трехмерный вид, иллюзию создает тень 1px :

--_shadow-depth-light: 0 1px var(--_border-light);
--_shadow-depth-dark: 0 1px var(--_bg-dark);
--_shadow-depth: var(--_shadow-depth-light);

Переходы кнопок

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

--_transition-motion-reduce: ;
--_transition-motion-ok:
  box-shadow
145ms ease,
  outline-offset
145ms ease
;
--_transition: var(--_transition-motion-reduce);

Все свойства вместе в селекторе

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"],
  input
[type="file"]
),
:where(input[type="file"])::file-selector-button {
 
--_accent-light: hsl(210 100% 40%);
 
--_accent-dark: hsl(210 50% 70%);
 
--_accent: var(--_accent-light);



--_text-light: hsl(210 10% 30%);
 
--_text-dark: hsl(210 5% 95%);
 
--_text: var(--_text-light);



--_bg-light: hsl(0 0% 100%);
 
--_bg-dark: hsl(210 9% 31%);
 
--_bg: var(--_bg-light);



--_input-well-light: hsl(210 16% 87%);
 
--_input-well-dark: hsl(204 10% 10%);
 
--_input-well: var(--_input-well-light);



--_padding-inline: 1.75ch;
 
--_padding-block: .75ch;



--_border-radius: .5ch;
 
--_border-light: hsl(210 14% 89%);
 
--_border-dark: var(--_bg-dark);
 
--_border: var(--_border-light);



--_highlight-size: 0;
 
--_highlight-light: hsl(210 10% 71% / 25%);
 
--_highlight-dark: hsl(210 10% 5% / 25%);
 
--_highlight: var(--_highlight-light);



--_ink-shadow-light: 0 1px 0 hsl(210 14% 89%);
 
--_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%);
 
--_ink-shadow: var(--_ink-shadow-light);



--_icon-size: 2ch;
 
--_icon-color-light: var(--_accent-light);
 
--_icon-color-dark: var(--_accent-dark);
 
--_icon-color: var(--accent, var(--_icon-color-light));



--_shadow-color-light: 220 3% 15%;
 
--_shadow-color-dark: 220 40% 2%;
 
--_shadow-color: var(--_shadow-color-light);
 
--_shadow-strength-light: 1%;
 
--_shadow-strength-dark: 25%;
 
--_shadow-strength: var(--_shadow-strength-light);
 
--_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%));
 
--_shadow-2:
   
0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)),
   
0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%))
 
;



--_shadow-depth-light: hsl(210 14% 89%);
 
--_shadow-depth-dark: var(--_bg-dark);
 
--_shadow-depth: var(--_shadow-depth-light);



--_transition-motion-reduce: ;
 
--_transition-motion-ok:
    box-shadow
145ms ease,
    outline-offset
145ms ease
 
;
 
--_transition: var(--_transition-motion-reduce);
}

Кнопки по умолчанию отображаются рядом со светлой и темной темой.

Адаптации темной темы

Значение шаблона статических реквизитов -light и -dark становится ясным, когда установлены реквизиты темной темы:

@media (prefers-color-scheme: dark) {
 
:where(
    button
,
    input
[type="button"],
    input
[type="submit"],
    input
[type="reset"],
    input
[type="file"]
 
),
 
:where(input[type="file"])::file-selector-button {
   
--_bg: var(--_bg-dark);
   
--_text: var(--_text-dark);
   
--_border: var(--_border-dark);
   
--_accent: var(--_accent-dark);
   
--_highlight: var(--_highlight-dark);
   
--_input-well: var(--_input-well-dark);
   
--_ink-shadow: var(--_ink-shadow-dark);
   
--_shadow-depth: var(--_shadow-depth-dark);
   
--_shadow-color: var(--_shadow-color-dark);
   
--_shadow-strength: var(--_shadow-strength-dark);
 
}
}

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

Сниженная адаптация к движению

Если с этим посетителем движение в порядке, назначьте --_transition для var(--_transition-motion-ok) :

@media (prefers-reduced-motion: no-preference) {
 
:where(
    button
,
    input
[type="button"],
    input
[type="submit"],
    input
[type="reset"],
    input
[type="file"]
 
),
 
:where(input[type="file"])::file-selector-button {
   
--_transition: var(--_transition-motion-ok);
 
}
}

Несколько общих стилей

Для кнопок и полей ввода необходимо настроить inherit шрифтов, чтобы они соответствовали остальным шрифтам страницы; в противном случае они будут стилизованы браузером. Это также относится к letter-spacing . Установка line-height на 1.5 устанавливает размер почтового ящика, чтобы оставить тексту немного места сверху и снизу:

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"],
  input
[type="file"]
),
:where(input[type="file"])::file-selector-button {
 
/* …CSS variables */

 
font: inherit;
 
letter-spacing: inherit;
 
line-height: 1.5;
 
border-radius: var(--_border-radius);
}

Снимок экрана, показывающий кнопки после применения предыдущих стилей.

Стилизация кнопок

Регулировка селектора

Селектор input[type="file"] не является частью кнопки ввода, а псевдоэлемент ::file-selector-button , поэтому я удалил input[type="file"] из списка:

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"],
  input
[type="file"]
),
:where(input[type="file"])::file-selector-button {
 
}

Регулировка курсора и сенсорного управления

Сначала я придаю курсору стиль pointer , что помогает кнопке указать пользователям мыши, что она интерактивна. Затем я добавляю touch-action: manipulation , чтобы при нажатии не нужно было ждать, и наблюдаю за потенциальным двойным щелчком, благодаря чему кнопки начинают работать быстрее:

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"]
),
:where(input[type="file"])::file-selector-button {
 
cursor: pointer;
 
touch-action: manipulation;
}

Цвета и границы

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

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"]
),
:where(input[type="file"])::file-selector-button {
 


 
font-size: var(--_size, 1rem);
 
font-weight: 700;
 
background: var(--_bg);
 
color: var(--_text);
 
border: 2px solid var(--_border);
}

Снимок экрана, показывающий кнопки после применения предыдущих стилей.

Тени

К кнопкам применены несколько замечательных техник. text-shadow адаптируется к свету и темноте, создавая приятный тонкий вид текста кнопки, красиво расположенного поверх фона. Для box-shadow назначены три тени. Первый, --_shadow-2 , представляет собой обычную тень блока. Вторая тень — это обман зрения, из-за которого кнопка кажется немного скошенной. Последняя тень предназначена для выделения при наведении, первоначально ее размер равен 0, но позже ей будет присвоен размер и изменен переход, поэтому кажется, что она растет от кнопки.

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"]
),
:where(input[type="file"])::file-selector-button {
 


 
box-shadow:
    var
(--_shadow-2),
    var
(--_shadow-depth),
   
0 0 0 var(--_highlight-size) var(--_highlight)
 
;
 
text-shadow: var(--_ink-shadow);
}

Снимок экрана, показывающий кнопки после применения предыдущих стилей.

Макет

Я присвоил кнопке макет flexbox , в частности inline-flex макет, который соответствует ее содержимому. Затем я центрирую текст и выравниваю дочерние элементы по центру по вертикали и горизонтали. Это поможет правильно выровнять значки и другие элементы кнопок.

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"]
),
:where(input[type="file"])::file-selector-button {
 


 
display: inline-flex;
 
justify-content: center;
 
align-items: center;
 
text-align: center;
}

Снимок экрана, показывающий кнопки после применения предыдущих стилей.

Расстояние

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

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"]
),
:where(input[type="file"])::file-selector-button {
 


 
gap: 1ch;
 
padding-block: var(--_padding-block);
 
padding-inline: var(--_padding-inline);
}

Снимок экрана, показывающий кнопки после применения предыдущих стилей.

Сенсорный интерфейс и мышь

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

Обычно я обнаружил, что это не тот пользовательский интерфейс с кнопками во встроенных приложениях, поэтому я отключаю его, устанавливая для параметра user-select значение none. Цвета выделения касания ( -webkit-tap-highlight-color ) и контекстные меню операционной системы ( -webkit-touch-callout ) — это другие веб-ориентированные функции кнопок, которые не соответствуют общим ожиданиям пользователей кнопок, поэтому я удаляю их как хорошо.

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"]
),
:where(input[type="file"])::file-selector-button {
 


 
user-select: none;
 
-webkit-tap-highlight-color: transparent;
 
-webkit-touch-callout: none;
}

Переходы

Адаптивная переменная --_transition присваивается свойству перехода :

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"]
),
:where(input[type="file"])::file-selector-button {
 


 
transition: var(--_transition);
}

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

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"]
):where(:not(:active):hover) {
 
--_highlight-size: .5rem;
}

После фокусировки увеличьте смещение контура фокуса от кнопки, придав ему красивый вид фокуса, который кажется растущим изнутри кнопки:

:where(button, input):where(:not(:active)):focus-visible {
 
outline-offset: 5px;
}

Иконки

Для обработки значков в селектор добавлен селектор :where() для прямых дочерних элементов SVG или элементов с настраиваемым атрибутом data-icon . Размер значка задается с помощью настраиваемого свойства с использованием встроенных и блочных логических свойств. Устанавливается цвет обводки, а также drop-shadow соответствующая text-shadow . flex-shrink установлено значение 0 поэтому значок никогда не сжимается. Наконец, я выбираю значки с линиями и назначаю здесь эти стили с fill: none , round концами линий и соединениями линий:

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"]
) > :where(svg, [data-icon]) {
 
block-size: var(--_icon-size);
 
inline-size: var(--_icon-size);
 
stroke: var(--_icon-color);
 
filter: drop-shadow(var(--_ink-shadow));

 
flex-shrink: 0;
 
fill: none;
 
stroke-linecap: round;
 
stroke-linejoin: round;
}

Снимок экрана, показывающий кнопки после применения предыдущих стилей.

Настройка кнопок отправки

Я хотел, чтобы кнопки отправки имели слегка продвинутый вид, и добился этого, сделав цвет текста кнопок акцентным цветом:

:where(
 
[type="submit"],
  form
button:not([type],[disabled])
) {
 
--_text: var(--_accent);
}

Снимок экрана, показывающий кнопки после применения предыдущих стилей.

Настройте кнопки сброса

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

:where([type="reset"]) {
 
--_border-light: hsl(0 100% 83%);
 
--_highlight-light: hsl(0 100% 89% / 20%);
 
--_text-light: hsl(0 80% 50%);
 
--_text-dark: hsl(0 100% 89%);
}

Я также подумал, что было бы неплохо, если бы цвет контура фокуса соответствовал красному акценту. Цвет текста меняется от темно-красного к светло-красному. Я делаю цвет контура соответствующим этому ключевому слову currentColor :

:where([type="reset"]):focus-visible {
 
outline-color: currentColor;
}

Снимок экрана, показывающий кнопки после применения предыдущих стилей.

Настроить отключенные кнопки

Слишком часто отключенные кнопки имеют плохой цветовой контраст при попытке подчинить отключенную кнопку, поэтому она кажется менее активной. Я протестировал каждый набор цветов и убедился, что они прошли проверку, изменяя значение яркости HSL до тех пор, пока оценка не пройдет в DevTools или VisBug.

:where(
  button
,
  input
[type="button"],
  input
[type="submit"],
  input
[type="reset"]
)[disabled] {
 
--_bg: none;
 
--_text-light: hsl(210 7% 40%);
 
--_text-dark: hsl(210 11% 71%);

 
cursor: not-allowed;
 
box-shadow: var(--_shadow-1);
}

Снимок экрана, показывающий кнопки после применения предыдущих стилей.

Настройка кнопок ввода файлов

Кнопка ввода файла представляет собой контейнер для диапазона и кнопки. CSS может немного стилизовать входной контейнер, а также вложенную кнопку, но не диапазон. Контейнеру задается max-inline-size , поэтому он не станет больше, чем нужно, а inline-size: 100% позволит себе сжиматься и вмещать контейнеры меньшего размера, чем он есть. Цвет фона установлен на адаптивный цвет, который темнее, чем у других поверхностей, поэтому он выглядит за кнопкой выбора файла.

:where(input[type="file"]) {
 
inline-size: 100%;
 
max-inline-size: max-content;
 
background-color: var(--_input-well);
}

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

:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
 
appearance: none;
}

Наконец, к inline-end кнопки добавляется поле, чтобы отодвинуть текст диапазона от кнопки, создавая некоторое пространство.

:where(input[type="file"])::file-selector-button {
 
margin-inline-end: var(--_padding-inline);
}

Снимок экрана, показывающий кнопки после применения предыдущих стилей.

Особые исключения темной темы

Я придал основным кнопкам действий более темный фон для более контрастного текста, придав им более рекламный вид.

@media (prefers-color-scheme: dark) {
 
:where(
   
[type="submit"],
   
[type="reset"],
   
[disabled],
    form
button:not([type="button"])
 
) {
   
--_bg: var(--_input-well);
 
}
}

Снимок экрана, показывающий кнопки после применения предыдущих стилей.

Создание вариантов

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

Яркая кнопка

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

.btn-custom {
 
--_bg: linear-gradient(hsl(228 94% 67%), hsl(228 81% 59%));
 
--_border: hsl(228 89% 63%);
 
--_text: hsl(228 89% 100%);
 
--_ink-shadow: 0 1px 0 hsl(228 57% 50%);
 
--_highlight: hsl(228 94% 67% / 20%);
}

Пользовательская кнопка отображается светлым и темным цветом. Он ярко-синего цвета, как и типичные кнопки основного действия.

Большая кнопка

Этот стиль кнопки достигается путем изменения пользовательского свойства --_size . Отступы и другие элементы пространства относятся к этому размеру и масштабируются пропорционально новому размеру.

.btn-large {
 
--_size: 1.5rem;
}

Большая кнопка отображается рядом с пользовательской кнопкой, примерно в 150 раз больше.

Кнопка со значком

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

[data-icon="cloud"] {
 
--icon-cloud: url("https://api.iconify.design/mdi:apple-icloud.svg") center / contain no-repeat;

 
-webkit-mask: var(--icon-cloud);
 
mask: var(--icon-cloud);
 
background: linear-gradient(to bottom, var(--_accent-dark), var(--_accent-light));
}

Кнопка со значком отображается в светлой и темной темах.

Заключение

Теперь, когда вы знаете, как я это сделал, как бы вы‽ 🙂

Давайте разнообразим наши подходы и изучим все способы разработки в Интернете.

Создайте демо, пришлите мне ссылку в Твиттере , и я добавлю ее в раздел ремиксов сообщества ниже!

Ремиксы сообщества

Здесь пока смотреть нечего.

Ресурсы