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.
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.
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.
$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 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.
$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;
}
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
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;
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;
}
}
@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.
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,
);
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.