Кнопки – важнейший интерактивный компонент наших сайтов. Именно с их помощью пользователи совершают большинство действий, значит, их дизайн очень важен.
Базовые стили
Начинаем с определения основных стилей для всех кнопок:
:root {
--btn-font-size: 1em;
--btn-radius: 0.25em;
}
.btn {
display: inline-flex;
position: relative;
white-space: nowrap;
text-decoration: none;
line-height: 1;
padding: var(--space-xs) var(--space-sm);
border-radius: var(--btn-radius);
font-size: var(--btn-font-size);
color: var(--color-link);
}
Эти свойства не будут изменяться для кнопок разных видов и размеров:
position: relative
потребуется для позиционирования иконок внутри кнопок;white-space: nowrap
запрещает перенос текста подписи на другую строчку;text-decoration: none
убирает подчеркивание, так что класс.btn
теперь можно устанавливать и для ссылок.
Абстрагирование размера шрифта и величины скругления углов особенно полезно на ранних этапах разработки дизайн-системы, когда изменения вносятся очень часто. Паддинги связаны с основной системой отступов, так что они изменяются автоматически.
Вариации стилей
Чаще всего для кнопок создаются следующие состояния:
.btn--primary
– базовый стиль активных кнопок;.btn--secondary
– дополнительная версия кнопок, предназначенных для менее важных действий, хорошо сочетающаяся с основной (primary
) или акцентной (accent
);- .
btn--accent
– используется для выделения кнопок с действиями, требующими повышенного внимания пользователя (например, удаление); .btn[disabled]
– указывает пользователю, что кнопка неактивна.
/* themes */
.btn--primary {
// main button
background-color: var(--btn-primary-bg);
color: var(--btn-primary-label);
@include fontSmooth;
&:visited {
color: var(--btn-primary-label);
}
&:hover {
background-color: var(--btn-primary-hover);
}
&:active {
background-color: var(--btn-primary-active);
}
}
.btn--secondary {
// subtle version, used for secondary actions or in combo with primary/accent button
background-color: var(--btn-secondary-bg);
color: var(--btn-secondary-label);
&:visited {
color: var(--btn-secondary-label);
}
&:active {
background-color: var(--btn-secondary-active);
}
}
.btn--accent {
// used to draw special attention to the button (e.g. destructive actions)
background-color: var(--btn-accent-bg);
color: var(--btn-accent-label);
@include fontSmooth;
&:visited {
color: var(--btn-accent-label);
}
&:hover {
background-color: var(--btn-accent-hover);
}
&:active {
background-color: var(--btn-accent-active);
}
}
/* feedback */
.btn[disabled] {
cursor: not-allowed;
background-color: var(--btn-disabled-bg);
color: var(--btn-disabled-label);
box-shadow: none;
opacity: 0.6;
&:visited {
color: var(--btn-disabled-label);
}
}
Все цвета определяются в отдельном файле _colors.scss
. Подробнее о работе с цветами и темами в дизайн-системе вы можете прочитать в третьей статье серии.
Добавим в этот файл цвета для кнопок:
/* --------------------------------
Colors
-------------------------------- */
:root {
/* main colors */
--color-primary: #286bf4;
--color-primary-light: color-mod(var(--color-primary) tint(15%));
--color-primary-dark: color-mod(var(--color-primary) shade(15%));
--color-primary-bg: color-mod(var(--color-primary) alpha(20%));
--color-accent: #f5414f;
--color-accent-light: color-mod(var(--color-accent) tint(15%));
--color-accent-dark: color-mod(var(--color-accent) shade(10%));
--color-accent-bg: color-mod(var(--color-accent) alpha(20%));
/* shades - generated using chroma.js - 12 steps */
--black: #1d1d21;
--gray-10: #2e2e31;
--gray-6: #7b7a7d;
--gray-4: #a5a5a6;
--gray-3: #bbbbbc;
--gray-2: #d1d0d2;
--gray-1: #e8e7e8;
--white: white;
/* buttons */
--btn-primary-bg: var(--color-primary);
--btn-primary-hover: var(--color-primary-light);
--btn-primary-active: var(--color-primary-dark);
--btn-primary-label: var(--white);
--btn-secondary-bg: var(--gray-1);
--btn-secondary-active: var(--gray-2);
--btn-secondary-label: var(--gray-10);
--btn-accent-bg: var(--color-accent);
--btn-accent-hover: var(--color-accent-light);
--btn-accent-active: var(--color-accent-dark);
--btn-accent-label: var(--white);
--btn-disabled-bg: var(--gray-2);
--btn-disabled-label: var(--gray-10);
}
Миксин fontSmooth
предназначен для улучшения рендеринга шрифтов при использовании светлого текста на темном фоне. Этот стиль используется довольно часто для разных элементов, поэтому его стоит вынести в отдельный миксин.
// edit font rendering -> tip: use for light text on dark backgrounds
@mixin fontSmooth {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
Здесь нет мелких несущественных стилевых деталей вроде теней или состояния при фокусировке. Они уникальны для каждого проекта, поэтому нет смысла включать их в саму дизайн-систему – их следует настраивать поверх нее.
Размеры
Необходимо создать для кнопок несколько возможных размеров. Речь идет не об отзывчивых элементах, изменяющихся в разных брейкпоинтах, а об отдельных вспомогательных классах для кнопок разного размера независимо от вьюпорта.
Хороший подход: определить переменные размера с помощью calc()
.
:root {
--btn-font-size: 1em;
--btn-sm: calc(var(--btn-font-size) - 0.2em);
--btn-md: calc(var(--btn-font-size) + 0.2em);
--btn-lg: calc(var(--btn-font-size) + 0.4em);
--btn-radius: var(--radius);
}
/* button size */
.btn--sm {
font-size: var(--btn-sm);
}
.btn--md {
font-size: var(--btn-md);
}
.btn--lg {
font-size: var(--btn-lg);
}
.btn--full-width {
display: flex;
width: 100%;
justify-content: center;
}
Кнопки с иконками
В предыдущей статье серии мы разобрались с выравниванием иконок и текста. Тот же самый класс .icon-text-aligner
можно использовать для выравнивания подписей и иконок внутри кнопок.
<button class="btn btn--primary icon-text-aligner">
<span>Button</span>
<svg class="icon"><use href="#icon-arrow-right" xlink:href="#icon-arrow-right"/></svg>
</button>
У нас могут быть кнопки без текста, только с иконкой, поэтому стоит привязать стили к классу .icon
внутри .btn
и убедиться, что иконка наследует стили подписи, даже если самой подписи нет.
.btn {
display: inline-flex;
position: relative;
white-space: nowrap;
text-decoration: none;
line-height: 1;
padding: var(--space-xs) var(--space-sm);
border-radius: var(--btn-radius);
font-size: var(--btn-font-size);
color: var(--color-link);
transition: .2s;
&:active {
transition: none;
}
.icon {
/* icon inherits color of button label */
color: inherit;
flex-shrink: 0;
}
}
Группы кнопок
В основной CSS-файл также стоит включить стили для кнопочных групп. К счастью, Flexbox-модель позволяет легко располагать элементы в одном измерении:
/* buttons group */
.btns {
display: flex;
flex-wrap: wrap;
margin-bottom: calc(-1 * var(--space-xs));
> * {
margin-right: var(--space-xs);
margin-bottom: var(--space-xs);
&:last-of-type {
margin-right: 0;
}
}
}
Отзывчивые кнопки
Вся наша дизайн-система, описанная в предыдущих статьях, основана на относительных единицах em и двух CSS-переменных: --text-base-size
и --space-unit
. Если обновить их в медиа-запросе, сработает каскадный эффект для всех элементов, включая кнопки. Поэтому нет необходимости создавать дополнительные запросы для в файле _buttons.scss
.
_buttons.scss
В итоге у нас получился вот такой глобальный SCSS-файл для кнопок:
/* --------------------------------
Buttons
-------------------------------- */
:root {
--btn-font-size: 1em;
--btn-sm: calc(var(--btn-font-size) - 0.2em);
--btn-md: calc(var(--btn-font-size) + 0.2em);
--btn-lg: calc(var(--btn-font-size) + 0.4em);
--btn-radius: var(--radius);
}
.btn {
display: inline-flex;
position: relative;
white-space: nowrap;
text-decoration: none;
line-height: 1;
padding: var(--space-xs) var(--space-sm);
border-radius: var(--btn-radius);
font-size: var(--btn-font-size);
color: var(--color-link);
transition: .2s;
&:active {
transition: none;
}
.icon {
/* icon inherits color of button label */
color: inherit;
flex-shrink: 0;
}
}
/* themes */
.btn--primary {
// main button
background-color: var(--btn-primary-bg);
color: var(--btn-primary-label);
@include fontSmooth;
&:visited {
color: var(--btn-primary-label);
}
&:hover {
background-color: var(--btn-primary-hover);
}
&:active {
background-color: var(--btn-primary-active);
}
}
.btn--secondary {
// subtle version, used for secondary actions or in combo with primary/accent button
background-color: var(--btn-secondary-bg);
color: var(--btn-secondary-label);
&:visited {
color: var(--btn-secondary-label);
}
&:active {
background-color: var(--btn-secondary-active);
}
}
.btn--accent {
// used to draw special attention to the button (e.g. destructive actions)
background-color: var(--btn-accent-bg);
color: var(--btn-accent-label);
@include fontSmooth;
&:visited {
color: var(--btn-accent-label);
}
&:hover {
background-color: var(--btn-accent-hover);
}
&:active {
background-color: var(--btn-accent-active);
}
}
/* feedback */
.btn[disabled] {
cursor: not-allowed;
background-color: var(--btn-disabled-bg);
color: var(--btn-disabled-label);
box-shadow: none;
opacity: 0.6;
&:visited {
color: var(--btn-disabled-label);
}
}
/* button size */
.btn--sm {
font-size: var(--btn-sm);
}
.btn--md {
font-size: var(--btn-md);
}
.btn--lg {
font-size: var(--btn-lg);
}
.btn--full-width {
display: flex;
width: 100%;
justify-content: center;
}
/* buttons group */
.btns {
display: flex;
flex-wrap: wrap;
margin-bottom: calc(-1 * var(--space-xs));
> * {
margin-right: var(--space-xs);
margin-bottom: var(--space-xs);
&:last-of-type {
margin-right: 0;
}
}
}
Заключение
Это последняя статья из серии, посвященной созданию дизайн-системы CodyHouse. Библиотеку компонентов целиком вы можете найти здесь.
0 комментариев