Layout Patterns: How to Unite Layout Artists and Designers

Written by shepelev | Published 2023/03/11
Tech Story Tags: css | html | best-practices | css-selectors | learn-css | layout-patterns | layout-artists-and-designers | web-design

TLDRThis article will help improve the interaction between designers and layout artists to minimize errors and increase productivity. We are talking about the use of styles and components in figma, i.e. fonts, colors, padding, etc. The order of layers and clear naming – first of all, this reflects your level of professionalism.via the TL;DR App

This article will help improve the interaction between designers and layout artists to minimize errors and increase productivity. Do not take the article as the only correct approach.
The article is rich in practical examples. It will be useful to different specialists.
The design is the basis of a quality layout and helps you successfully continue the development of a web application.

Criteria for good design

  1. Standard properties of design elements (colors, fonts, sizes, padding, etc.)
  2. The principle of reuse. Changing some elements should lead to transformations of these elements in other parts of the layout. You should avoid copying elements and reuse them instead. We are talking about the use of styles and components in figma, i.e. fonts, colors, padding, etc.
  3. The order of layers and clear naming – first of all, this reflects your level of professionalism. You need to take the process responsibly.
  4. Work out the issue of the functioning of the project on mobile and touch devices. Keep in mind that there is no hover event on these devices. Don’t forget to use this in your layouts (there is a hover text on desktop, while there is no such case on mobile devices).
  5. To simplify the work of layout artists, the designer should make videos of the created animations.

Layout recommendations

  1. Pixel Perfect is an outdated solution. It prevailed for raster layouts, in which it was not possible to refine the dimensions of elements. At this stage, browser extensions were used to overlay design images. There is no need to use this approach.
  2. You should not use global tag selectors for such elements as a, li, ui, h, p, etc. Create classes for more precise selection. For example, you can bind the wrapper class to body .main h1 {}. Globally, h1 is bad, .h1 is good. Remember the principle of reusability!
  3. Try not to set the height of elements (input button, etc.) with padding if they have a static height in the design. The height of elements should be set in pixels. So, the designer sets specific pixel dimensions for an element, and changing the number of lines or internal content will affect the original dimensions. If this cannot be avoided, for example, a button is a 2-line font wrap, be careful with the internal content. Perhaps you should create an additional class.
  4. Use size types correctly. For layout elements, it is best to use pixels rather than other units of measurement. The design is usually created in pixels, so you should not interfere with the original parameters. Percentages also need to be applied carefully. If you are using anything other than 25% 50% 100%, you are probably doing something wrong. 50% if we divide equally 2 blocks inside 1 parent, and 25% if it is about 4 blocks. For fonts and typography, you should use relative values ​​rem, em, and %. Setting the font size to px prevents adjusting the font size in web browsers, which some people use.

Using ready-made ui systems and bootstrap

If you use bootstrap and other ui systems in projects where all elements are custom and can accept any logic and forms, you will most likely generate additional wrappers and crutches, while adding unused functionality in the form of js and style code. Therefore, I would recommend avoiding this and customizing everything to fit your needs if you use custom visuals. Bootstrap often has a lot of things that we do not need to use. So, we remove one part and customize the other. Another problem may arise when changing the ui of the libraries used in the frameworks. If bootstrap, or any other ui system, is easy to adapt to your needs and doesn’t require complex customization, you can use it without any problems.

Let’s analyze the patterns

The atomic class approach will be used as an example. This may slightly increase the amount of html code. However, this problem can be solved by creating a small number of accurate classes. The advantage of this method is the reuse of css styles, as well as the minimization of the number of class wrappers.

Let’s consider color standards for elements, fonts, icons, etc.

  1. Create and reuse styles for colors. There is no need to use an eyedropper, inherit the color, or copy hex codes.
  2. A small number of shades of the same color in the project will help you avoid unnecessary confusion. Don’t create “50 shades of gray”. The project needs about 6 primary and 4 secondary colors.
  3. Transferring color styles to a ui kit (dashboard) is necessary to get information about color codes and transfer it without using Figma. For example, you can send a printed brand book to your customer.
  4. The style names in figma must match the color variable names in the code. This will help the developer navigate and avoid opening figma to view the color.

Examples of names

$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;
Let’s create color and fill classes for use in html.
@mixin color($name, $color) {
  .bg-#{$name}  {
    background: $color !important;
  }
  .color-#{$name} {
    color: $color !important;
  }
}
Connect
@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);
Use bg-{{name}} .bg-primary .bg-danger for `background-color` 
Use color-{{name}} for `color` 

The multiplicity of indents and sizes

The multiplicity of indents and sizes is the designer’s observance of the principle of dividing all such dimensions by the same integer. The standard is 4px, which means that all indents and sizes must be the product of 4 by some integer. These are 4px, 8px, 12px, 16px, 20px, etc. It is allowed to use 1px and 2px.
If necessary, the multiplicity can be changed (for example, 22px or 11px), but it is better to at least keep a multiplicity of 2px if the base is 4px. Otherwise, we will have to divide the pixel when centering the elements.
For example, a button has a font size of 11px and a height of 40px. We place our font in the center of the button. 40 - 11 = 29/2 = 14.5 (top and bottom indent)
The browser can handle pixel division – that’s not a problem. There is the question of aesthetics and ease of page layout process. When splitting a layout along a pixel grid in figma, you won’t have to go beyond its boundaries.
Don’t forget to put the information on the indents into the ui kit, which must contain all the design agreements.
Create a sheet that is necessary to generate classes:
$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,
);
Then use a mixin to create classes:
@mixin size-classes($screen: '') {
  @each $index, $size in $sizes {
    .m#{$screen}-#{$index} {
      margin: $size !important;
    }
    .mx#{$screen}-#{$index} {
      margin-right: $size !important;
      margin-left: $size !important;
    }
    .my#{$screen}-#{$index} {
      margin-top: $size !important;
      margin-bottom: $size !important;
    }
    .ml#{$screen}-#{$index} {
      margin-left: $size !important;
    }
    .mr#{$screen}-#{$index} {
      margin-right: $size !important;
    }
    .mt#{$screen}-#{$index} {
      margin-top: $size !important;
    }
    .mb#{$screen}-#{$index} {
      margin-bottom: $size !important;
    }

    .p#{$screen}-#{$index} {
      padding: $size !important;
    }
    .px#{$screen}-#{$index} {
      padding-right: $size !important;
      padding-left: $size !important;
    }
    .py#{$screen}-#{$index} {
      padding-top: $size !important;
      padding-bottom: $size !important;
    }
    .pl#{$screen}-#{$index} {
      padding-left: $size !important;
    }
    .pr#{$screen}-#{$index} {
      padding-right: $size !important;
    }
    .pt#{$screen}-#{$index} {
      padding-top: $size !important;
    }
    .pb#{$screen}-#{$index} {
      padding-bottom: $size !important;
    }
  }
}
@include size-classes;
@include app-classes;

@include media(lg) {
  @include size-classes('-lg');
  @include app-classes('-lg');
}

@include media(md) {
  @include size-classes('-md');
  @include app-classes('-md');
}

@include media(sm) {
  @include size-classes('-sm');
  @include app-classes('-sm');
}
I wouldn’t recommend creating classes for negative indents and adding more than 20 variations. In this case, we will create a lot of rarely used classes and greatly increase the css file for initial rendering. In our example, we create 1 size and add 14 classes (from the padding and margin mixin) * 4 (all resolutions) – 56 classes in total. So, it is worth reducing the number of sizes in the sheet.

Creating variables:

$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;
Until the first size-52, we inherit sizes from $sizes. For the rest, it is enough to create sizes that are multiples of our approvals.
Inside the team, it is necessary to prohibit developers from using sizes. They have to use variables like $size-4 $size-32, etc., and percentage values ​​are allowed only in the format of 100 50 25 percent. If you still have to deviate from this order, be sure to leave a comment. This will help you avoid misunderstandings and clarify that this is part of the design.
&__subcategories {
  max-width: 600px;
}
Use m`{-media}?`-`{size}` (x-axis, y-axis) for `margin`.
Use p`{-media}?`-`{size}` (x-axis, y-axis) for `padding`.
Create `icon-{size}` classes for icons
Only 3 classes are most often needed:
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;
}

Font styles

As in the case of colors and indents, all fonts must be brought into figma styles and put into a ui kit, without creating dozens of variations of size and thickness, as well as letter and line spacing. As a rule, the following is enough: sizes – h1, h2, h3, h4: default text, small text. Styles – regular, medium, bold.
The layout artist needs to correctly connect our fonts, which means specifically telling the browser where to download regular, bold fonts, etc. Otherwise, the browser will create its bold style, which won’t match the layout.
Use classes to set fonts for elements like .h1, .h2, or at least @mixin h1. Mixins are bad since they duplicate properties instead of reusing them. When working with the layout, select the desired font using font-weight.
Connect
@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;
}
Using mixins for base classes:
.h3 {
  @include h3;

  @include media(md) {
    @include h4;
  }
}
@mixin font($size: 16px,  $line-height: 22px, $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(46px, 52px, 2px, 600, $size-32);
}

@mixin h2 {
  @include font(30px, 30px, 1.5px, 500, $size-24);
}

@mixin h3 {
  @include font(22px, 26px, 0.5px, 400, $size-16);
}

@mixin h4 {
  @include font(18px, 26px, 0.3px, 400, $size-8);
}

@mixin text {
  @include font;
}

@mixin text-sm {
  @include font(14px, 20px);
}

@mixin text-default {
  @include text;
  @include media(tablet) {
    @include text-sm;
  }
}
Adding margin bottoms to headings is acceptable. These indents are usually standard for each font size. You can remove indentation like this: - .h1 .mb-0

Element properties

The designer also puts all the repeating styles of the elements (shadows, radii, borders) into the ui kit. There is no need to create a lot of variations.
The layout looks like this:
$font: 'Rubik', sans-serif;
$radius-block: $size-6;
$radius-element: $size-6;
$border-element: $size-2;
$show-block: 0 0 $size-38 rgba($color-element, 0.1);
$animate-time: 0.2s;

Checkpoints

The designer specifies the checkpoints for your application and puts the information into the ui kit. Typically, the sizes correspond to screen sizes of different devices.
Create variables:
$breakpoints: (
  xl: 1200px,
  lg: 992px,
  md: 768px,
  sm: 576px,
);
Create a mixin for ease of use of media conditions:
@mixin media($Device) {
  @media screen and (max-width: map-get($breakpoints, $Device) - 1px) {
    @content;
  }
}

Utility classes

@mixin app-classes($screen: '') {
  .d#{$screen}-n {
    display: none !important;
  }
  .d#{$screen}-b {
    display: block !important;
  }
  .d#{$screen}-f {
    display: flex !important;
  }
  .fw#{$screen}-w {
    flex-wrap: wrap !important;
  }
  .fw#{$screen}-n {
    flex-wrap: nowrap !important;
  }
  .fd#{$screen}-c {
    flex-direction: column !important;
  }
  .fd#{$screen}-r {
    flex-direction: row !important;
  }
  .fb#{$screen}-100 {
    flex-basis: 100% !important;
  }
  .ai#{$screen}-c {
    align-items: center !important;
  }
  .ai#{$screen}-fs {
    align-items: flex-start !important;
  }
  .ai#{$screen}-fe {
    align-items: flex-end !important;
  }
  .as#{$screen}-fs {
    align-self: flex-start !important;
  }
  .as#{$screen}-fe {
    align-self: flex-end !important;
  }
  .as#{$screen}-c {
    align-self: center !important;
  }
  .jc#{$screen}-fe {
    justify-content: flex-end !important;
  }
  .jc#{$screen}-fs {
    justify-content: flex-start !important;
  }
  .jc#{$screen}-c {
    justify-content: center !important;
  }
  .jc#{$screen}-sb {
    justify-content: space-between !important;
  }

  .bg#{$screen}-n {
    background: none !important;
  }

  .br#{$screen}-n {
    border: none !important;
  }

  .w#{$screen}-100 {
    width: 100% !important;
  }
  .h#{$screen}-100 {
    height: 100% !important;
  }

  .w#{$screen}-50 {
    width: 50% !important;
  }
  .h#{$screen}-50 {
    height: 50% !important;
  }

  .w#{$screen}-25 {
    width: 50% !important;
  }
  .h#{$screen}-25 {
    height: 50% !important;
  }

  .f#{$screen}-l {
    font-weight: 300;
  }
  .f#{$screen}-r {
    font-weight: 400;
  }
  .f#{$screen}-m {
    font-weight: 600;
  }
  .f#{$screen}-b {
    font-weight: 800;
  }
}
This is the class approach to layout design. For example, we often need to align blocks horizontally: in this case, d-f will be enough, and we won’t have to consistently create wrapper classes.
Use `d-f` for `display-flex: flex`.
Use `ai-c` for `align-items: center`.
The list can be constantly replenished as needed. If the property consists of 2 words, use the letters of the words `text-align` = `ta`.
If the property consists of 1 letter and does not conflict with others, use `display` = `d`.
In case of conflict between the first and last letters, use `border` = `br` or part of the word according to the logic `background` = `bg`.
Try to use class layout without any scss variables and mixins. `class="d-f m-4 m-md-4"` – permissible. `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"` – bad. In such cases, a class is created with a description of the properties inside it.
`class="d-f custom-class"` – not forbidden, but sometimes it is more convenient and preferable to write the property inside the class: `display: flex`.
Make it a rule not to write more than 5 classes in a block.

Z-index

Connect `@include z-index(key name)`. The z-index values ​​are set in increments of 10 to leave space for errors and tweaks.
When adding a new key, you need to take into account any z-index conflicts that may occur:
$z-index: (
  modal: 30,
  header: 20,
  menu: 10,
  default: 1,
);

Conclusion

You need to thoroughly approach the process of layout design. This will help you avoid difficulties in the implementation of the project and ensure easy, unpretentious cooperation between specialists in various fields.

Written by shepelev | Senior Ruby on Rails Developer
Published by HackerNoon on 2023/03/11