Fluid Space
font sizing | page elements



Designing with fluid type scalesDesigning with a fluid space palettePainting with a fluid space palette

Fluid Type Scales

https://clearleft.com/posts/designing-with-fluid-type-scales

 

Over the past few years I’ve been lucky enough to work with some very smart designers and developers who have helped me hone my thoughts and ideas into a more tangible approach to fluid responsive design – particularly with regard to typography.

Although every project has different requirements, type size variation on a phone is usually relatively conservative, given that there’s limited horizontal space available. On a large laptop or desktop display it’s often desirable to use much more dramatic type scales to make the most of the extra space. The question is how to accommodate both screen sizes while respecting everything in between.

The big idea that triggered this train of thought now seems very simple:

  1. Define a type scale for a small screen
  2. Define a type scale for a large screen
  3. Tell the browser to interpolate between the two scales, based on the current viewport width.

This results in a set of type sizes which is always “in tune” with itself and feels at home on any device, without needing to manually specify sizes for x number of arbitrary breakpoints. For example we can just say H2s are always “size 4” and trust the calculation to generate a suitable size heading for everybody.

A chart showing scaling fluid fonts

Visualising what this means

 

In the example above, I defined a typographic scale of 1.2x at 320px (mobile-ish) and 1.333x at 1500px (desktop-ish). At any viewport width in between, the set of type sizes is proportional, although I haven’t needed to manually specify any additional values. I dropped a line at 1024px to show the automatically-calculated font size values at that viewport size. For this example I generated the values using a Google Sheet but this can be elegantly replicated in CSS as described in this excellent blog post by Clearleft developer Trys.

Here’s how these values can translate into design:

A simple example showing typography automatically “breathing” into the available space in a tablet-ish viewport size.

 

A simple example showing typography automatically “breathing” into the available space in a tablet-ish viewport size.

Trys has created a live version of the above example so you can see it in action: Watch the type breathe as you resize your viewport.

Exactly how you define your two type scales will depend on your product’s fonts, visual style, content, layout, audience, etc. This approach is not a substitute for good design, rather it encourages focusing design effort into the creation of a robust system. This should help to speed up future activity and decision making, as well as bake in consistency by establishing a “palette” of related type sizes.

The user benefit to this approach is that typography will always look “right”, regardless of the device being used. This is not always the case with the standard approach, where your brand new tablet might land you on the wrong side of the nearest breakpoint

 

designing with a fluid space palette

By James Gilyead

Space is the ultimate fundamental; the most ubiquitous “thing” there is. In fact our brains generally perceive space as the “nothing” between the “things” they prefer to fixate on. We move through this silent, invisible, three-dimensional emptiness with very little resistance and rarely think about it at all. So is it any wonder space is an often-overlooked element of design, appearing almost by accident between the bits we spend our time carefully crafting?

Thoughtful spacing is a key ingredient of effective design. It can group or separate content, help communicate your brand character, pack as many of your products as possible into a single viewport, or afford a beautiful, distraction-free reading experience.

In this world of many screens, we typically design digital layouts with tighter spacing for smaller screens and relax the spacing as more real estate becomes available on larger screens. There is, however, no single standardised approach to defining how space behaves from viewport to viewport.

In my experience, visual designers tend to deal with space on an ad-hoc basis, creating components and layouts that look “right” at a number of specific viewport widths. This can leave developers with the task of deciphering spatial relationships within and between components, either following the designer’s file with pixel-precision, or by adjusting and standardising spacing to ensure order and repeatability in the code. Since spacing is often not well documented in style guides, this can lead either to the faithful reproduction of unintentional decisions, or a thoughtful refactor which doesn’t follow a designer’s intent.

What we need is a way to make and communicate deliberate decisions to eradicate doubt and ensure we’re all singing from the same stylesheet…

Enter the matrix

During the last few projects Trys and I have worked on together, we’ve developed some ways to help streamline the relationship between design and development. Step one was to define a systematic approach to fluid responsive typography. Step two has been to formulate a similar approach to space, which I’ve been calling the “space matrix”. It starts off pretty much the same as our typographic scales:

  1. Define a type space scale for a small screen
  2. Define a type space scale for a large screen
  3. Tell the browser to interpolate between the two scales, based on the current viewport width.

The space scales we’ve been working with so far have been multiplied directly from the body font size of each project, without defining different scale multipliers for min and max viewports. It’s important to assign size names to these values to make them easy to refer to. We use t-shirt sizes: (S)mall, (M)edium, (L)arge, etc. For example:

Although I keep track of decimal places for documentation, I round all values to the nearest pixel when working with them in FigmaAlthough I keep track of decimal places for documentation, I round all values to the nearest pixel when working with them in Figma.

The multiplier values in this example have emerged from real-world projects as reasonable steps to provide enough spatial contrast for grouping or separating content, padding inside a button, or big, confident spacing for hero slats. These values can of course be adjusted to suit any project, before or during the design process. We’ve found that we need more nuanced space options nearer the base font size, and fewer options at the larger end of the scale. Hence the smaller increments are 0.25 and the larger increments are whole numbers.

Correctly implemented, these individual space values are already fluidly responsive – an (S) space flexes depending on the viewport width: In this example, 16px @min, through to 18px @max, and a proportional size within that range at any viewport width in between. Admittedly, a 2px flex is pretty underwhelming. To make our space palette work even harder though, we can pair up these values to add a dimension of attitude, increasing the variance between the space @min and @max:

Individual space values are subtly responsive by default. Space value pairs can offer much more dynamic space optionsIndividual space values are subtly responsive by default. Space value pairs can offer much more dynamic space options.

These new space pairs flex with much more drama than the individual space values:

Content typeCard titleContent lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Viewport

@MIN**@MAX**

SHOW SPACE

The space between the card’s items is defined as an individual space value, which only changes subtly between viewports. The card’s padding is defined as a space pair, which changes more dramatically.

With the space matrix we can simply define those space pairs and use them anywhere that particular size and attitude is appropriate.

In this way we can build up a palette of fluid space sizes to repeat throughout our design. Because these sizes are calculated from the current viewport width, the layout will simply “breathe” to make the most of the available space, and we can forget about breakpoint-based space rules. We don’t need to worry about the latest iPad size or the new Google hugePhone. Our design will automatically look proportional on any device regardless of its exact viewport width. There’s no limit to how many spaces you might define, although I prefer to work with the fewest possible.

"Because these sizes are calculated from the current viewport width, we can forget about breakpoint-based space rules"

KISS: Keep it simple and systematic

In the same way a layout grid helps guide us to design in an orderly fashion without second guessing every size and space decision, the space matrix can help us to create consistent designs which adapt gracefully to look at home on any screen. We can make certain design decisions much more quickly: What size should my grid’s gutters be? What about its columns? Button padding? Elements within a card? What about the space between cards? In all of these cases we can now pick a suitable size from the space palette. If nothing comes close enough, we can always add a size.

imgimg

Every space in our designs can now be described by name.

Creating a bespoke space matrix does introduce some cognitive overhead early in the design process but it can dramatically speed things up once the project gets rolling. Think of it as engineering a custom set of rails to design on. I start practically every design project by defining the font and the body copy size. Once I know that magic number I can step up and down through my default multiplier increments to identify my space matrix values and start mapping out layout grids and generic components. A developer can start setting up the design foundations in code at the same time because we already have a common language and a shared approach. In other words, we’ve agreed on a set of – malleable – project-specific constraints to ensure we’ll be building the same thing in the same way.

Get started

To help you incorporate a space matrix in your next project, we’ve designed a tool to quickly calculate a set of space values for you. This tool also generates CSS ready to be included in your project’s code. We’re also working on a Figma plugin to automate some of the initial asset generation and speed up the first stages of the designer’s project setup.

If you’re looking for more details on the CSS magic that makes this work in the browser, Trys has written an excellent blog post about that.

painting with a fluid space palette

By Trys Mudford

When it comes to design systems, it's all too easy to focus on the components, the chunky bricks that make up majority of the digital experiences we use. But personally, I'm more excited about the cement that holds it all together.

Gaps, margin, padding, gutters. Whatever you call it, space is everywhere on a website. It's the glue that holds components together, and dictates whether they sit in harmony, or feel disjointed. But in my experience, intentional, systemised and elegant placement of space is so often overlooked by developers and designers alike.

We developers tend to fall into two camps: the "eyeing it brigade", and the "treating the design as gospel clan". The first group see a gap between two components and think "well… that looks roughly like 2rem, let's go with that.". The other bunch get their rulers out and measure the precise gap, popping a 1.9375rem into the system. Neither is ideal. The first runs the risk of disregarding the nuanced decisions that go into a design. The second doesn't allow for the designer making an honest mistake. But importantly, both groups generate duplicate code, every time they set a gap. This issue is only accelerated when a larger team of designers & developers work on a project.

Preventing entropy

As I blogged recently, intentional friction points and shared language help prevent entropy in our design systems. We have a rule of thumb that applies to the big things (components), as well as the small (type and space):

"Before adding to a system, first consider whether anything similar exists, and if so, can the design can be adapted to use the system after all."

By designing from the same system, we can shortcut many of the fiddly micro-decisions about gaps, and as developers, feel empowered to roll out space intentionally on our sites.

A space palette

We're used to the concept of a colour palette. Brand guidelines surface the pre-agreed sets of colours the can be used, and their varying tints and shades, and designers have to are meant to stick to them. But what if we applied the same thinking to space?

Until now, Utopia has focused on harmonious and fluid typographic scales that help to ensure your text looks "at home" on any device. But we knew from the start that type was only one side of the coin. In our latest release, we've taken the foundations of a fluid type scale, and built a lightweight but extensible space system atop it, creating a "fluid space palette".

"Step 0" of our type scale becomes the t-shirt size "S", and acts as our origin for further spaces. We then multiply up and down to create a variety of intentional spaces. The multipliers are up to you and your specific design, but we tend to find you need more options close to the origin ("S"), and fewer further out.

A space matrix, comprising of individual fluid space values at their smallest and largest size

T-shirt sizing for space isn't a new concept—most systems map a "size" to a static value. But by building the space system on top of a fluid base value, each "size" is inherently fluid out of the box, rendering smaller on mobile screens, and gradually growing bigger on larger devices.

James has written a post documenting how a designer can arrive at these values, and use them within their design tool. For now, I'm going to carry on talking about how a developer can use this palette.

Interpolating between spaces

Now we have a set of individual space units, we can interpolate between them. "XS → S", "M → 3XL", and even reverse interpolations of "2XL → 2XS".

An interpolation of an XL to 2XL space

Out of the box, Utopia provides all the positive "single-step pairs" (2XS → XS, XS → S, S → M etc). Where an individual space value (M) grows a slight amount, these single-steps grow at a slightly steeper rate.

Pairs are perfect for handling internal component padding between small and large screens. Thanks to custom properties and CSS locks, you don't need to lock off these values every time you use them, it's a simple as:

.c-card {
  padding: var(--space-s-m); // 18px → 33px
}

Custom space pairs

To take it one step further, you can interpolate between any two individual space sizes, creating incredibly steep slopes (3XS → 4XL), perfect for handling spacing for hero slats, or even reverse slopes that get smaller as you expand the screen width (2XL → XS). These custom space pairs are fully configurable within the space calculator on Utopia.

A collection of custom space pairs

Using a fluid space palette

Utopia exposes these fluid spaces as custom properties, which makes them entirely opt-in. There are two main ways to use them:

In your CSS

As demonstrated with the earlier internal padding example, you can use fluid space values directly in your CSS. It's not limited to padding though, anything that can take a pixel value, can also use these fluid values. Margin, padding, grid-gap, clip-path, transform all work great with Utopia:

.o-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap: var(--space-s-l); // 18px → 44px
}

Utility classes

When used appropriately, utility classes can be a great way to 'paint' space onto a web page. I love the flow utility that Andy Bell documented, so I often start by creating a few versions of that with fluid space values:

.u-flow > * + * {
  margin-top: var(--space-s);
}

.u-flow--l > * + * {
  margin-top: var(--space-l); 
}

.u-flow--s-m > * + * {
  margin-top: var(--space-s-m); 
}

These can then be used in my HTML to provide bulletproof and fluid spacing between any number of items:

<article class="c-card u-flow">
  <img src="" alt="" />
  <h2>Card title</h2>
  <p>Card description</p>
</article>

Painting with space

The most empowering part of this system, is the control it gives me, as a developer, to make the call on how things should shrink or grow on different devices. In the past, I would be given a 'desktop' mockup, a 'mobile' mockup, and occasionally a 'tablet' sized mockup, and I'd have to try and shoehorn a system that worked between all three sizes. Now, with a fluid space palette, and a common language between design and development, I rarely get need more than a large screen design file. This leaves me to make the most appropriate call on how components should be spaced, or what the most appropriate gutter is to make the design feel at home on a small device.

I can't begin to explain how much of a difference it has made to my personal development process to be able to check a consistent design, and have the control at my fingertips to create a harmoniously spaced website. But more importantly, this shared language has significantly improved the way I communicate with the design team. And by spending time upfront deciding on the shared design foundations, we can each focus on what we’re best at.

Want to try it out?

If this has whetted your appetite to start building with fluid space, head on over to the fluid space calculator and create your own responsive and intuitive space system. The tool visualises the space system, and generates all the CSS you'll need to implement it in your project. Furthermore, we're working on a Figma plugin to make the designer's life easier too—watch this space.

 

Scroll to Top