First Published On:
April 25, 2024
Last Updated:
May 4, 2024


Figure 1. Animation demonstrating state layer implementation.

No items found.


An interesting quick read about the inspiration for this system

I think about typography in a weird way. I think about hierarchy in three dimensions instead of two. Let me explain.

One of the most common ways to explain hierarchy in visual design is by describing it in terms of “what the viewer reads first.” I’ve found that helpful. It’s not hard to find a popular example of it, as it pops up on the front page of reddit about two or three times a year:

A popular example of hierarchy in action.

But when properly scaled, you can almost perceive a depth in this graphic, as though you were looking “into” the interface.

I doubt I’m the first to develop this mental model, but I admit I haven’t looked into the academic research yet.

Still, I think this will become more relevant as VR and AR become more useful. How might our approach to hierarchy change when we’re confined not by the bounds of a page or a screen, but by our own field of vision? One day, instead of scrolling, we might swim through our information.

Those days are still quite far ahead of us, though. In the meantime, LiftKit type simply lays the foundations.

The Type System

In LiftKit, there is one type system with two families: regular and bold. They look like this, and their specs are below.

Class Default Weight Emphasized Weight Size Line Height Letter Spacing
display1 400 700 4.235 1.129 -0.022
display2 400 700 2.618 1.272 -0.022
titleA 400 700 2.058 1.272 -0.022
titleB 400 600 1.618 1.272 -0.02
titleC 400 600 1.272 1.272 -0.017
heading 600 700 1.129 1.272 -0.014
subheading 400 600 0.885 1.272 -0.007
body 400 600 1 1.618 -0.011
callout 400 600 0.943 1.272 -0.009
label 500 700 0.835 1.272 -0.004
caption 400 600 0.786 1.272 -0.007
overline 400 600 0.786 1.272 0.0618

Responsiveness (h4)

The type system assumes the :root font size equals 1vw, but it establishes guardrails to stay accessible at various breakpoints. You can see these here:

<code snippets for global media queries>

On mobile devices, .display1 and .display2 have smaller font sizes that remain in step with the scaling system. The larger jumps they take look good on desktops and large screens, but mobile devices simply don’t have enough real estate for it.

How the Scaling Works

LiftKit type is asymmetrical, meaning the steps in-between each level of text is not always equal. At the larger end of the scale, styles scale by a factor of 1.618 or even more. At the lower end, they can scale by as little as a factor of 1.06. In other words, the difference in size between .titleA and .titleB is greater than that between .label and .caption.

The justification for this proportional asymmetry lies in applications for larger screens. LiftKit’s global scaling system is based on the golden ratio, but if you scale your type that way, you can’t have more than a handful of different sizes. We need a greater variety of type styles than a pure scale factor of 1.618 would allow. The obvious solution would be to simply use a smaller scale factor, but this raised problems of its own.

Smaller scale factor doesn’t solve the problem either, because at the small end of the spectrum, you would need it to be very small indeed. And if we were to choose such a small scale factor, then we would need a ludicrous number of styles in order to generate the largest variant we would need.

No, the goal is to cover the highest number of use cases with the fewest number of type styles. At the same time, the type styles themselves should have intuitive naming conventions that generally describe the role of each type level in the interface.

My solution was to try combining the best of both Apple and Googles’ solutions to this problem. Why just them? Well, I figured that these two brands’ design systems govern the overwhelming majority of user interfaces we interact with on a day-to-day basis. As such, they have a vested interest in optimizing their systems to be as broadly appealing as possible while remaining simple enough for both internal and third-party developers to keep consistent. Plus, Google’s design departments are famous for the level of overthinking they put into this kind of thing. We all remember the “blue” study. At the same time, Apple’s whole thing is being prettier than Google. (Apple pickme’s, you can send your hate mail here).

Therefore, the two systems gave me a great foundation for the end result of what millions of dollars worth of design work produces. The HIG type system, and the Material 3 type system. Standing on the shoulders of these giants, I decided to try combining the best of both worlds into a single system, and that’s where LiftKit’s came from.

Comparing the two’s systems:

  • HIG is more prescriptive, making it very clear what rules designers should follow
  • M3 is more suggestive, giving designers more freedom

But with freedom comes risk, and in M3’s case, the risk is designers implementing styles in an unpleasing way.

In my opinion, it’s simply too ambiguous how Material’s type styles are supposed to relate to one another.

For example, they have five categories: display, heading, title, body, and label. Each category has three sizes: large, medium, and small.

Already this raises a number of questions. For example, is “medium” supposed to be the “default”? It’s reasonable to assume that, but it’s not explicitly stated.

Furthermore, if I’m using body medium, should I only use title, heading, display, and label “medium” as well? Or can you mix and match display small, heading large, and body medium?

I could go on, but it would deserve its own article.

HIG, meanwhile, isn’t getting off easy either. HIG has 11 type styles, and these are named more specifically. Nevertheless, you wind up with several styles sharing the same traits: headline and body, for example, have the same size and line height. Footnote, caption 1, and caption 2 are also the same size and line height, and footnote (which appears higher in the list) has a lower emphasis than “caption 2.” I’m sure there’s a reason for this, but for the designer simply reading their documentation without any outside context, it’s not self-evident. And that leads to further opportunities for confusion, poor implementation, and inconsistent styling.

LiftKit doesn’t solve all these problems. But in my opinion, it’s less prone to mistaken implementation. Does this restrict creativity? Yes. However, my experience has been that people confident in their creative abilities don’t rely heavily on design systems in the first place. The ones I’ve met usually wind up creating design systems of their own. I figured that those types of people who decide to try LiftKit will be coming into it intending to change it up anyway, and this type system makes it easy for them to do so.

Recommended Usage

Recommended Use

LiftKit doesn’t have many best practices beyond those that apply to typography design in general. All the rules you may already know about hierarchy are still valid. What few recommendations LiftKit does provide are just that: recommendations. That being said, here are a few do’s and don’ts.

  • Antialiasing
    • Do keep the default antialiasing rules set in the global CSS. This makes text appear sharp and crisp, the way it does in design programs like Figma.
    • Don’t remove it, unless you discover some kind of critical display error.
  • Combining multiple type styles
    • Do skip a type level when combining styles .titleC and larger.
    • Don’t skip type levels when combining .heading and smaller.
    • Caution: Be careful when skipping more than one level.
  • Applying margins and padding
    • Do use LiftKit’s built-in utility classes to set margin and padding on text elements.
    • Don’t use LiftKit’s default spacing variables for typography. These will not account for the offset created by the text elements’ line height, and it will result in disproportionate scaling.
  • Multiple font families
    • Do: Feel free to use more than 1 typeface in the system.
    • Don’t: Use more than 3.
  • Any more than three typefaces and the layout will lose all sense of cohesion. If it were up to me, no one would be allowed to use more than 2. However, there are scenarios where you require a monotype font for small font sizes like overlines, or you want to have different fonts for display, titles, and the rest.
  • LiftKit was designed with a single typeface, Inter, because this guaranteed differences in hierarchy were not reliant on font family. Font family should never be a primary driver in hierarchical differentiation, because the actual drivers of that differentiation (weight, color, size) have well-studied effects on how we interpret hierarchy. Font family, however, does not.
    • Do: Use the same typeface for styles with related roles.
    • Don’t: Use different typefaces for styles with related roles.
  • <aside>💡 Caution: Using multiple typefaces may break the golden lattice. This is because different typefaces have different intrinsic leading, x-heights, etc.
  • </aside>
  • Mixing up font families within semantically-similar type styles can imply differences in importance that you don’t intend. The result is the user will have to expend more effort to navigate the UI.
  • Custom styles
    • Do feel free to add custom styles in-between the existing ones.
    • Don’t go smaller than caption.
    • Do scale custom styles using the global scaling conventions.
    • Don’t scale on non-golden scale factors like 1.25. It will break the golden lattice. Instead, scale by factors derived from multiples or n-roots of phi, such as 1.618, 1.272, 1.128, and 1.062.

Color Grading and Typography

It’s typically a bad idea to have all your text be the same exact color unless you’re in high-contrast mode for accessibility reasons. It helps establish hierarchy to have larger text be higher contrast.

However, there’s some debate about this. Material’s position is designs should be accessible by default. HIG’s, meanwhile, well…

Accessibility Issues with Apple’s Typographic Color Grading

Look at this example from the official iOS design kit in Figma, published by Apple:


If you plug these different label colors into the WebAIM contrast ratio checker, you’ll find that only the default passes all accessibility checks.

  • Secondary fails at all levels for normal text, and only passes WCAG AA for Large text.
  • Tertiary fails at every level
  • Quaternary fails at every level, but harder

You may think it’s because the background is gray. It’s not. It’s the same even if it’s pure white.

The lightest you can go against a pure white background while remaining at least WCAG AA compliant at the average font size of 16px is #757575, or a lightness value of 46.

Apple gets around this by having an “Increase Contrast” option in its accessibility settings that you can activate, presuming you have the necessary level of vision to locate the menu option in the first place. There’s also a “differentiate without color” option, but that doesn’t affect text opacity.

LiftKit’s Solution (h4)

It’s not groundbreaking really. LiftKit just… doesn’t do that.

Still, if accessibility simply does not concern you (maybe you’re making a slide deck for a group of 5 people who you know for a fact have no trouble with low-contrast designs), it’s recommended you control color grading via opacity.

Because LiftKit is light/dark agnostic, you shouldn’t set static font colors to control grading, as the levels of difference may not be the same between modes.


Resources that mention this topic

No items found.