Паттерны верстки. Как объединить верстальщиков и дизайнеров

в 7:10, , рубрики: css, css grid, css3, scss, верстальщик, верстка, верстка сайтов, графический дизайн, дизайн, дизайнер, интерфейсы, Оболочки, паттерны

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

Работа богата практическими примерами. Она будет полезна специалистам разного профиля.

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

Критерии хорошего дизайна:

  1. Стандартизированные свойства элементов дизайна (цвета, шрифты, размеры, отступы и т.д.)

  1. Принцип переиспользуемости. Изменение одних элементов должно приводить к преобразованиям этих элементов в других частях макета. Нужно избегать копирования элементов.- переиспользуйте их. Речь идёт об использовании стилей и компонентов в figma: шрифтов, цветов, отступов и прочего.

  1. Порядок в слоях и понятный нейминг - прежде всего это ваш профессионализм. Необходимо подходить к процессу ответственно.

  1. Прорабатывать функционирование проекта на мобильных и touch устройствах. Помните об отсутствии hover event  на данных девайсах, не забывайте использовать это в своих макетах. (на десктопе при наведении появляется дополнительный текст, а на мобильных устройствах подобный кейс не учтен.)

  1. Для упрощения работы верстальщика дизайнеру стоит делать видео созданных анимаций.

Рекомендации по верстке:

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

  1. Не стоит использовать глобальные селекторы по тегам для элементов a, li, ui, h, p и тд, Создавайте классы для более точного выбора. Например, можно завязаться на класс обертку в body .main h1 {}. Глобально h1 - плохо .h1 - хорошо. Помним про принцип переиспользуемости!

  1. Не задавать высоту элементам (input button и тд) с помощью padding. Дизайнер задает конкретные параметры элемента в пикселях, поэтому изменение количества строк или внутреннего контента  повлияет на исходные размеры. Поэтому height у элементов задаем в пикселях.

  1. Лучше использовать пиксели в верстке, а не другие единицы измерения. Дизайн изначально создан в пикселях, поэтому не стоит вмешиваться в исходные параметры. Проценты тоже необходимо применять аккуратно,  если вы используете что-то помимо 25% 50% 100% то, вероятно, вы делаете что-то не так. 50% если делим поровну 2 блока внутри 1 родителя ну и 25% соответственно 4 блока.

Использование готовых ui систем и bootstrap.

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

Разберем паттерны.

Ссылка на пример https://github.com/jtapes/styles-example

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

Рассмотрим цветовые стандарты для - элементом, шрифтов, иконок и тд.

  1. Создавайте и переиспользуйте стили для цветов, не нужно красить пипеткой, наследуя цвет, или копировать hex коды.

  1. Малое количество оттенков одного цвета в проекте поможет избежать ненужной путаницы. Не создавайте "50 оттенков серого". Для проекта оптимально около 6 основных и 4 вариаций серого.

  1. Вынесение цветовых стилей в ui kit (dashboard) нужно для получения информации о кодах цвета и передачи без использования Figma. Например, можно отправить распечатку заказчику для brandbook.

  1. Названия стилей в 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,
);

Заключение

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

Автор: Владислав

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js