xl6: 576px
Space is the distance between elements. It determines visual patterns. Systemizing space improves the visual harmony through predictable and proportional values, helping our users navigate and focus on what’s important.
Principles
Rhythmic
Consistent rhythm is harmonious. By designing proportional and rhythmic space, we ensure the quality of our digital experiences.
Simple but flexible
Space needs to be simple to be consistent and flexible to be considerate. Our approach unites both.
The Space Array
The following values may be used to create whitespace between elements:
xl5: 356px
xl4: 220px
xl3: 136px
xl2: 84px
xl: 52px
l: 32px
m: 20px
s: 12px
xs: 8px
xs2: 4px
xs3: 2px
none: 0px
Concepts
We use the following terms to talk about different concepts of space. Some of them also apply to layouts.
1. Inset
Inset refers to the inner space that elements may have. Examples are cards (inset across all 4 sides) or sections (top/bottom inset).
Horizontal (left/right) inset always has to be
$space-m
(20px). This ensures that for
any page, all content within different inset elements still stay
aligned with each other.
2. Stack
Stack refers to vertical space between elements.
A strict stack refers to spacing where the distance between all elements is identical, whereas a loose stack refers to one where space might vary. In both cases, space values should follow the space array.
3. Grid gutter
Like for horizontal inset, the
Layout Grid
gutter always must be $space-m
(20px).
Any other value would reduce the grid track sizes, and therefore break
the grid.
For example, when attempting to create more whitespace between columns, some tracks can be left empty to create whitespace.
4. Inline
Inline refers to horizontal space between elements that are arranged next to each other, and that are not part of the layout grid, for example the contents of a card. Any space from the space array may be applied.
Optical Space
Our space system aims to control optical space, not only theoretical space. Theoretical space refers to the values used in our code, whereas optical space refers to the space perceived by our eyes.
For example, typography usually adds a bit of extra top/bottom space due to its line height. An image might have uncropped extra space, that invokes the impression of a larger space than was defined in our code.
We want optical space to match our space array, but we also want to have consistent space values in our code. Therefore we aim to remove any discrepancies between theoretical and optical space. For example, we apply baseline cropping to typography, and crop images perfectly.
Also, whenever we explicitely define distance between elements, we should avoid creating optical space that does not follow our space array.
For example, having an element with
$space-m
(20px) margin top and
$space-m
(20px) padding top (and no
border in between) would theoretically follow our system, but
practically creates a space (40px) that was not defined in our array.
A similar value from the space array should be unsed instead, like
$space-l
(32px).
Note that there are a lot of exceptions to this rule where optical space naturally ends up being a value outside of our space array. Examples are the left/right space around the Layout Container, or empty Layout Grid tracks.
Elaboration
The core requirements of space is that it should be rhythmic, simple and flexible. On a conceptual level, each of those requirements are quite easy to solve.
Rhythmic is about determining a visual rhythm for our elements and maintaining that. With only requirements for rhythm, consistency would be easy. But pure rhythm wouldn’t be very flexible.
To have flexibility, we would need to tailor the rhythm for each individual element and purpose. For example, a table with content might need a compact rhythm, while long paragraphs in a rich text needs more space. To serve flexibility, the optimal idea would be to choose essentially any value to tailor the position of (and between) every element to its purpose.
Simple on the other hand, requires some kind of system in order to keep things predictable, maintainable and scalable. But conceptually, simplicity is in absolute contrast to flexibility.
Our solution to unite these three conceptual ideas is to design an array (a list) of space variations that is
proportional (to ensure rhythm)
finite (to ensure simplicity)
differentiated (to ensure flexibility)
Linear vs non-linear scales
When creating the array of possible space values, there were two different options: A linear or a non-linear scale. For non-linear scales, the formulas we considered were exponential growth and the Fibonacci sequence. With the purpose in mind – rhythmic, simple and flexible – there were kind of clear instructions on what kind of mathematical systems could achieve this.
Linear example: 4, 8, 12, 16, 20, 24, ...
Exponential example: 4, 8, 16, 32, 64, 128, ...
Fibonacci example: 4, 8, 12, 20, 32, 52, ...
Linear arrays are very flexible, and while they could be rhythmic, they offer virtually no limitation which quickly takes the designer from complete freedom to making small decisions difficult because the differences between the array values are too small.
Exponential arrays on the other hand have the exact opposite problem. They can be rhythmic, and they can be simple. The problem with exponential arrays however is flexibility; the large differences in values makes it difficult to deal with nuances in differentiation – ultimately making the system too simple and rigid.
The Fibonacci approach really is the mixture of those two, combining quite a lot of flexibility with quite a lot of simplicity. Not extreme on any end, but that’s not really the purpose of our whitespace. Our whitespace needs to be rhythmic, simple and flexible, not just two of those.
The Fibonacci sequence in detail
We use a modified version of the Fibonacci sequence (Golden Ratio) starting with numbers 4 and 8. To generate the next value, you add the two previous values. 4+8=12, 8+12=20, ...
With this formula, we are given an array that has enough variations to suit a number of different use cases and design problems while still proportionally elegant and with a finite number of possible combinations.
Results
Our approach is a system that reduces the manual decision-making that was previously handled per individual use case, essentially devouring a lot of time for both designers and developers. The result of this is higher consistency throughout our experiences, less time spent manually defining space but still generating high aesthetic quality.
Tokens
Token | Value | Example |
---|---|---|
$space-gutter | 1.25rem | |
$space-gutter-px | 20px | |
$space-gutter-raw | 20 | |
$space-xl6 | 36rem | |
$space-xl6-px | 576px | |
$space-xl6-raw | 576 | |
$space-xl5 | 22.25rem | |
$space-xl5-px | 356px | |
$space-xl5-raw | 356 | |
$space-xl4 | 13.75rem | |
$space-xl4-px | 220px | |
$space-xl4-raw | 220 | |
$space-xl3 | 8.5rem | |
$space-xl3-px | 136px | |
$space-xl3-raw | 136 | |
$space-xl2 | 5.25rem | |
$space-xl2-px | 84px | |
$space-xl2-raw | 84 | |
$space-xl | 3.25rem | |
$space-xl-px | 52px | |
$space-xl-raw | 52 | |
$space-l | 2rem | |
$space-l-px | 32px | |
$space-l-raw | 32 | |
$space-m | 1.25rem | |
$space-m-px | 20px | |
$space-m-raw | 20 | |
$space-s | 0.75rem | |
$space-s-px | 12px | |
$space-s-raw | 12 | |
$space-xs | 0.5rem | |
$space-xs-px | 8px | |
$space-xs-raw | 8 | |
$space-xs2 | 0.25rem | |
$space-xs2-px | 4px | |
$space-xs2-raw | 4 | |
$space-xs3 | 0.125rem | |
$space-xs3-px | 2px | |
$space-xs3-raw | 2 | |
$space-none | 0rem | |
$space-none-px | 0px | |
$space-none-raw | 0 |