Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Данная статья поможет улучшить взаимодействие между дизайнерами и верстальщиками для минимизации ошибок и повышения продуктивности работы.
Работа богата практическими примерами. Она будет полезна специалистам разного профиля.
Дизайн является основой качественной верстки и помогает успешно продолжить создание веб-приложения.
Критерии хорошего дизайна:
Стандартизированные свойства элементов дизайна (цвета, шрифты, размеры, отступы и т.д.)
Принцип переиспользуемости. Изменение одних элементов должно приводить к преобразованиям этих элементов в других частях макета. Нужно избегать копирования элементов.- переиспользуйте их. Речь идёт об использовании стилей и компонентов в figma: шрифтов, цветов, отступов и прочего.
Порядок в слоях и понятный нейминг - прежде всего это ваш профессионализм. Необходимо подходить к процессу ответственно.
Прорабатывать функционирование проекта на мобильных и touch устройствах. Помните об отсутствии hover event на данных девайсах, не забывайте использовать это в своих макетах. (на десктопе при наведении появляется дополнительный текст, а на мобильных устройствах подобный кейс не учтен.)
Для упрощения работы верстальщика дизайнеру стоит делать видео созданных анимаций.
Рекомендации по верстке:
Pixel perfect - решение устаревшее. Оно преобладало для растровых макетов, в которых не было возможности уточнить размеры элементов. На этом этапе использовались расширения в браузере для наложения изображений дизайна. Подобный подход использовать не нужно.
Не стоит использовать глобальные селекторы по тегам для элементов a, li, ui, h, p и тд, Создавайте классы для более точного выбора. Например, можно завязаться на класс обертку в body .main h1 {}. Глобально h1 - плохо .h1 - хорошо. Помним про принцип переиспользуемости!
Не задавать высоту элементам (input button и тд) с помощью padding. Дизайнер задает конкретные параметры элемента в пикселях, поэтому изменение количества строк или внутреннего контента повлияет на исходные размеры. Поэтому height у элементов задаем в пикселях.
Лучше использовать пиксели в верстке, а не другие единицы измерения. Дизайн изначально создан в пикселях, поэтому не стоит вмешиваться в исходные параметры. Проценты тоже необходимо применять аккуратно, если вы используете что-то помимо 25% 50% 100% то, вероятно, вы делаете что-то не так. 50% если делим поровну 2 блока внутри 1 родителя ну и 25% соответственно 4 блока.
Использование готовых ui систем и bootstrap.
В прожектах у которых все элементы кастомные с возможностью принимать любую логику и формы, используя bootstrap и прочие ui системы, вы скорее всего будете обвязывать их дополнительными обертками и костылями, при этом неся за собой неиспользуемый функционал в виде js и style кода. Поэтому в проектах с индивидуальным визуалом стоит этого избегать и кастомизировать все под свои нужды.
Разберем паттерны.
Ссылка на пример https://github.com/jtapes/styles-example
В качестве примера будет использован подход атомарных классов. При этом немного может увеличивается объем html кода. Однако данный подход решается точным и лаконичным написанием небольшого количества классов. Преимуществом данного метода в переиспользование сss стилей, а также минимизация создания классовых оберток.
Рассмотрим цветовые стандарты для - элементом, шрифтов, иконок и тд.
Создавайте и переиспользуйте стили для цветов, не нужно красить пипеткой, наследуя цвет, или копировать hex коды.
Малое количество оттенков одного цвета в проекте поможет избежать ненужной путаницы. Не создавайте "50 оттенков серого". Для проекта оптимально около 6 основных и 4 вариаций серого.
Вынесение цветовых стилей в ui kit (dashboard) нужно для получения информации о кодах цвета и передачи без использования Figma. Например, можно отправить распечатку заказчику для brandbook.
Названия стилей в figma должны совпадать с названиями переменных цветов в коде. Это поможет разработчику ориентироваться и не открывать каждый раз figma для просмотра цвета.
Примеры названий
main, primary, success, danger, warning
$color-main: #464c54;
$color-primary: #ff2e00;
$color-primary-hover: #d72d00;
$color-primary-active: #bd2200;
$color-success: #25b782;
$color-blue: #7da9e0;
$color-withe: #f4f4f4;
$color-gray-light: #ccd1d9;
$color-gray: #8c9299;
$color-element: #545c66;
$color-element-light: #656d78;
Создадим классы цветов и заливки для использования в html.
@mixin color($name, $color) {
.bg-#{$name} {
background: $color !important; /* stylelint-disable-line declaration-no-important */
}
.color-#{$name} {
color: $color !important; /* stylelint-disable-line declaration-no-important */
}
}
Подключим
@include color('base', $color-main);
@include color('primary', $color-primary);
@include color('success', $color-success);
@include color('blue', $color-blue);
@include color('withe', $color-withe);
@include color('light', $color-gray-light);
@include color('gray', $color-gray);
@include color('element', $color-element);
@include color('element2', $color-element-light);
для `background-color` используем bg-{{name}} .bg-primary .bg-danger
для `color` используем color-{{name}}
.color-primary .color-danger
Кратность отступов и размеров
Кратностью отступов и размеров это соблюдение дизайнером принципа деления всех таких измерений на одно целое число. Стандартом является 4px - значит, все отступы и размеры должны быть результатом произведения 4, на какое-либо целое число.
4px, 8px, 12px, 16px, 20px и тд. Разрешается использовать 1px и 2px.
При необходимости кратность можно поменять (например, 22px или 11px), но лучше соблюдать ее хотя бы к 2px. если базовая 4px.
В ином случае нам придется делить пиксель при центровке элементов.
Например, у кнопки размер шрифта 11px, а высота кнопки 40px.
Делаем наш шрифт по центру кнопки.
40 - 11 = 29/2 = 14.5 (отступ сверху и низу)
Браузер сможет справиться с делением на пиксели - это не проблема. Здесь стоит вопрос эстетичности и легкости процесса верстки страницы. А при разбиении макета по пиксельной сетке в figma не придется выходить за его границы.
Не забываем выносить информацию по отступам в ui kit, тут должны быть все договоренности по дизайну.
Создаем лист, необходимый для генерации классов:
$sizes: (
0: 0,
4: 4px,
8: 8px,
12: 12px,
16: 16px,
20: 20px,
24: 24px,
28: 28px,
32: 32px,
36: 36px,
40: 40px,
44: 44px,
48: 48px,
);
Используем в миксине и создаём классы:
@mixin sizes-classes($screen-name: '') {
@each $index, $size in $sizes {
.m#{$screen-name}-#{$index} {
margin: $size !important;
}
.mx#{$screen-name}-#{$index} {
margin-right: $size !important;
margin-left: $size !important;
}
.my#{$screen-name}-#{$index} {
margin-top: $size !important;
margin-bottom: $size !important;
}
.ml#{$screen-name}-#{$index} {
margin-left: $size !important;
}
.mr#{$screen-name}-#{$index} {
margin-right: $size !important;
}
.mt#{$screen-name}-#{$index} {
margin-top: $size !important;
}
.mb#{$screen-name}-#{$index} {
margin-bottom: $size !important;
}
.p#{$screen-name}-#{$index} {
padding: $size !important;
}
.px#{$screen-name}-#{$index} {
padding-right: $size !important;
padding-left: $size !important;
}
.py#{$screen-name}-#{$index} {
padding-top: $size !important;
padding-bottom: $size !important;
}
.pl#{$screen-name}-#{$index} {
padding-left: $size !important;
}
.pr#{$screen-name}-#{$index} {
padding-right: $size !important;
}
.pt#{$screen-name}-#{$index} {
padding-top: $size !important;
}
.pb#{$screen-name}-#{$index} {
padding-bottom: $size !important;
}
}
}
@include sizes-classes;
@include project-classes;
@include media(lg) {
@include sizes-classes('-lg');
@include project-classes('-lg');
}
@include media(md) {
@include sizes-classes('-md');
@include project-classes('-md');
}
@include media(sm) {
@include sizes-classes('-sm');
@include project-classes('-sm');
}
Не советую создавать классы для отрицательных отступов и делать более 20 вариаций, так как мы создадим массу редко используемых классов и сильно увеличим css файл для первичной отрисовки. В примере при создании 1 размера создаются 14 классов (из миксина padding и margin) * 4 (все разрешения) - получается 56 классов, поэтому стоит сокращать количество размеров в листе.
Создание переменных:
$size-0: map-get($sizes, 0);
$size-4: map-get($sizes, 4);
$size-8: map-get($sizes, 8);
$size-12: map-get($sizes, 12);
$size-16: map-get($sizes, 16);
$size-20: map-get($sizes, 20);
$size-24: map-get($sizes, 24);
$size-28: map-get($sizes, 28);
$size-32: map-get($sizes, 32);
$size-36: map-get($sizes, 36);
$size-40: map-get($sizes, 40);
$size-44: map-get($sizes, 44);
$size-48: map-get($sizes, 48);
$size-52: 52px;
$size-60: 60px;
$size-64: 64px;
$size-80: 80px;
$size-84: 84px;
$size-88: 88px;
$size-100: 100px;
До первого size-52 наследуем размеры от $sizes. Для остальных достаточно создать размеры, кратные нашим согласованиям.
Внутри команды необходимо запретить разработчикам использовать размеры, нужно обязательно использовать переменные по типу $size-4 $size-32 и тд, а процентные значения допускаются только в формате 100 50 25 процентов, Если все же придется отступить от такого порядка - оставляйте комментарий. Это позволит избежать недопонимания и пояснит, что это - часть дизайна.
&__subcategories {
max-width: 600px; // Размер второй колонки в каталоге из дизайна
}
для `margin` использовать m`{-media}?`-`{size}` (x,y) - оси
.m-1 .ml-2 mt-md-1 .mx-4 .my-2
для `padding` использовать p`{-media}?`-`{size}` (x,y) - оси
.p-1 .pl-2 pt-md-1 .px-4 .py-2
для иконок можно создать классы - `icon-{size}`
Чаще всего необходимы только 3 класса:
icon-16 icon-24 icon-32
svg {
width: 100%;
height: 100%;
fill: currentColor;
}
.icon-16 {
width: $size-16;
height: $size-16;
}
.icon-24 {
width: $size-24;
height: $size-24;
}
.icon-32 {
width: $size-32;
height: $size-32;
}
Стили шрифтов
Как и в случае с цветами и отступами все шрифты необходимо занести в стили figma и вынести в up kit, не создавая при этом десятки вариаций толщины и размера, межбуквенных и межстрочных интервалов. Обычно достаточно следующего: размеры - h1, h2, h3, h4: default text, small text. Начертания - regular, medium, bold.
Верстальщику необходимо правильно подключить наши шрифты, нужно конкретно указать браузеру, откуда загружать шрифты regular, bold и т.д., В противном случае браузер сделает начертание bold самостоятельно. Это не будет соответствовать макету.
Используйте классы для задания шрифтов у элементов по типу .h1 .h2 или в крайнем случае @mixin h1. Миксины плохи тем что, дублируют, а не переиспользуют свойства. В верстке нужный шрифт выбираем с помощью font-weight.
Подключение
@font-face {
src: url('https://fonts.gstatic.com/s/rubik/v14/iJWKBXyIfDnIV7nBrXw.woff2') format('woff2');
font-family: 'Rubik';
font-weight: 100 500;
font-style: normal;
font-display: swap;
}
@font-face {
src: url('https://fonts.gstatic.com/s/rubik/v14/iJWKBXyIfDnIV7nBrXw.woff2') format('woff2');
font-family: 'Rubik';
font-weight: 600 800;
font-style: normal;
font-display: swap;
}
Таблица размеров и типов:
100: Thin;
200: Extra Light (Ultra Light);
300: Light;
400: Normal;
500: Medium;
600: Semi Bold (Demi Bold);
700: Bold;
800: Extra Bold (Ultra Bold);
900: Black (Heavy).
Не используйте свойства шрифтов.
Если вдруг по какой-либо причине это необходимо, комментарий обязателен.
Использование миксинов для базовых классов
.h3 {
@include h3;
@include media(md) {
@include h4;
}
}
@mixin font($size: 18px, $line-height: 24px, $letter-spacing: 0.1px, $weight: 400, $bottom: false) {
margin: 0;
font-family: $font;
font-weight: $weight;
font-size: $size;
line-height: $line-height;
letter-spacing: $letter-spacing;
user-select: text;
@if $bottom {
margin-bottom: $bottom;
}
}
@mixin h1 {
@include font(48px, 54px, 2px, 600, $size-32);
}
@mixin h2 {
@include font(32px, 32px, 1.5px, 500, $size-24);
}
@mixin h3 {
@include font(24px, 28px, 0.5px, 400, $size-16);
}
@mixin h4 {
@include font(20px, 28px, 0.3px, 400, $size-8);
}
@mixin text {
@include font;
}
@mixin text-sm {
@include font(16px, 22px);
}
@mixin text-default {
@include text;
@include media(tablet) {
@include text-sm;
}
}
Зашивать margin bottom в заголовки допустимо, обычно эти отступы для каждого размера шрифта стандартизированы дизайном.
Убрать отступы можно следующим образом: - .h1 .mb-0
Свойства элементов
Все повторяющиеся стили у элементов (тени, радиусы, бордеры) дизайнер также выносит в ui kit. Не рекомендуется делать много вариаций.
В верстке выглядит это примерно так:
$font: 'Rubik', sans-serif;
$radius-block: $size-8;
$radius-element: $size-8;
$border-element: $size-4;
$show-block: 0 0 $size-40 rgba($color-element, 0.1);
$animate-time: 0.2s;
Контрольные точки
Дизайнер указывает информацию в ui kit: какие точки перестроения интерфейса у нашего приложения. Обычно размеры соответствуют размерам экранов на разных устройствах.
Создаём переменные:
$breakpoints: (
xl: 1200px,
lg: 992px,
md: 768px,
sm: 576px,
);
Создаем миксин для удобства использования медиа условий:
@mixin media($Device) {
@media screen and (max-width: map-get($breakpoints, $Device) - 1px) {
@content;
}
}
Сетка проекта
Это описание колонок, по которым будут располагаться будущие блоки. Под разные размеры устройств сетка практически всегда будет отличаться, как и межколоночный интервал.
Описываем правила в стилях:
@import 'variables';
$columns-count: 12;
$gutter: $size-16;
$width: 100% / $columns-count;
@mixin grid($breakpoint: '') {
$prefix: if($breakpoint == '', '', '-');
@for $i from 1 through $columns-count {
.col#{$prefix}#{$breakpoint}-#{$i} {
width: $width * $i;
@if $i != 1 {
margin-left: $gutter;
}
}
}
@for $i from 1 through $columns-count {
.off#{$prefix}#{$breakpoint}-#{$i} {
margin-left: calc(#{$gutter} + #{$width * $i});
}
}
}
@include grid;
@each $breakpoint, $value in $breakpoints {
@media (max-width: $value) {
@include grid($breakpoint);
}
}
Кастомные классы
Для всех кастомных классов используем префикс:
$custom: 'pr'; // префикс для кастомных классов
.#{$custom}-container {
margin: 0 auto;
padding: 0 map-get($sizes, 24);
width: 100%;
max-width: 1140px !important;
@include media(md) {
padding: 0 map-get($sizes, 16);
}
@include media(md) {
max-width: 556px !important;
}
}
Классы утилиты
@mixin project-classes($screen-name: '') {
.d#{$screen-name}-n {
display: none !important;
}
.d#{$screen-name}-b {
display: block !important;
}
.d#{$screen-name}-f {
display: flex !important;
}
.fw#{$screen-name}-w {
flex-wrap: wrap !important;
}
.fw#{$screen-name}-n {
flex-wrap: nowrap !important;
}
.fd#{$screen-name}-c {
flex-direction: column !important;
}
.fd#{$screen-name}-r {
flex-direction: row !important;
}
.fb#{$screen-name}-100 {
flex-basis: 100% !important;
}
.ai#{$screen-name}-c {
align-items: center !important;
}
.ai#{$screen-name}-fs {
align-items: flex-start !important;
}
.ai#{$screen-name}-fe {
align-items: flex-end !important;
}
.as#{$screen-name}-fs {
align-self: flex-start !important;
}
.as#{$screen-name}-fe {
align-self: flex-end !important;
}
.as#{$screen-name}-c {
align-self: center !important;
}
.jc#{$screen-name}-fe {
justify-content: flex-end !important;
}
.jc#{$screen-name}-fs {
justify-content: flex-start !important;
}
.jc#{$screen-name}-c {
justify-content: center !important;
}
.jc#{$screen-name}-sb {
justify-content: space-between !important;
}
.bg#{$screen-name}-n {
background: none !important;
}
.br#{$screen-name}-n {
border: none !important;
}
.w#{$screen-name}-100 {
width: 100% !important;
}
.h#{$screen-name}-100 {
height: 100% !important;
}
.w#{$screen-name}-50 {
width: 50% !important;
}
.h#{$screen-name}-50 {
height: 50% !important;
}
.w#{$screen-name}-25 {
width: 50% !important;
}
.h#{$screen-name}-25 {
height: 50% !important;
}
.f#{$screen-name}-l {
font-weight: 300;
}
.f#{$screen-name}-r {
font-weight: 400;
}
.f#{$screen-name}-m {
font-weight: 600;
}
.f#{$screen-name}-b {
font-weight: 800;
}
}
Это и есть верстка классовым подходом. Например, очень часто нам нужно выровнять блоки по горизонтали: в данном случае будет достаточно d-f, и не придётся каждый раз создавать классы-обертки.
Для `display-flex: flex`используем `d-f`
Для `align-items: center`- `ai-c`
Список можно постоянно пополнять по мере необходимости Если свойство состоит из 2 слов, используем буквы слов `text-align` = `ta`
Если свойство состоит из 1 буквы и не конфликтует с другими - `display` = `d`
При конфликте первой и последней буквы - `border` = `br` или часть слова по логике `background` = `bg`
Старайтесь максимально использовать классовую верстку без переменных и миксинов scss.
`class="d-f m-4 m-md-4"` - допустимо
`class="d-f m-4 m-md-4 d-f m-4 m-md-4 d-f m-4 m-md-4 d-f m-4 m-md-4"` - Плохо. В таких случаях создается класс с описанием свойств внутри него.
`class="d-f custom-class"` - не запрещено, но иногда удобней и предпочтительней написать свойство в классе: `display: flex`.
Возьмите за правило не писать больше 5 классов в блоке.
Не забывайте про классы w-100 h-100, w-50 h-50, w-25 h-25
Z-index
Подключение `@include z-index(наименование ключа)`
Значения z-index заданы с шагом 10 для того, чтобы оставить место для ошибок и настроек.
При добавлении нового ключа необходимо предусмотреть все конфликты с существующей картой z-index:
$z-index: (
modal: 30,
header: 20,
menu: 10,
default: 1,
);
Заключение
Необходимо основательно подходить к процессу верстки и дизайна макета. Это поможет избежать трудностей в реализации проекта и обеспечит легкое, незатейливое сотрудничество между специалистами различных сфер.