Cleaning up our font system

Continuing the discussion from We need a "large fonts" and "small fonts" theme to ship with Discourse:

I did a quick audit of where we currently stand with font definitions across Discourse, and well… we have 50+ uniquely defined font-size values across the app (I’m not even going to begin considering the possible amount of variation from cascading ems). Some of these are equivalent to each other, but we need to simplify and be consistent.






Getting started
An easy first step is to cut the px and % definitions in favor of ems. Following that, it would make sense to start looking at values like .9em .929em .93em and combining them to simplify the massive number of similar-but-different font sizes we have.

:sparkles: More to come :sparkles:


As of 2017-2018, rem should be an interesting unit to use. I like that since it doesn’t change with their parent. Is that in the plan?


This week I’ve been working on simplifying the overall number of fonts we use. Essentially taking our most used font-sizes and merging the near-sizes into them. Through this a system starts to emerge from our most common sizes.

(These em values use 14px as the base)

.786em 11px
.857em 12px
1em 14px
1.143em 16px
1.286em 18px
1.429em 20px
1.857em 25px
2.286em 32px
2.571em 36px

We’re only slightly off from a classic typopgrahy scale

Once the system is established, we can create a sass function to manage scaling sizes across the app from the base size. At that point if someone wanted to set the base to 16px instead of 14px, all fonts would scale proportionately. Setting font sizes in our CSS would be easier too, because it could look something like:

font-size: font(-1); = 12px
font-size: font(0); = 14px base
font-size: font(1); = 16px
font-size: font(2); = 18px


I’ve been reading some more articles about type systems from other designers, this one specifically seemed to carry on some of thoughts I’ve already been putting together: Responsive Typographic Scales in CSS

The system looks like this:

$font-up-6: 2.296em;
$font-up-5: 2em;
$font-up-4: 1.7511em;
$font-up-3: 1.5157em;
$font-up-2: 1.3195em;
$font-up-1: 1.1487em;
$font-0: 1em;
$font-down-1: .8706em;
$font-down-2: .7579em;
$font-down-3: .6599em;
$font-down-4: .5745em;
$font-down-5: .5em;
$font-down-6: .4355em;

…and essentially functions like a ladder. Your base font-size is $font-0 and you traverse up and down the scale as you need larger/smaller fonts.

This works well when you start nesting values too. If you nest em values, say a grandparent element set to 1.7511em a parent element set to .8706em and a child set to 1.3195em you have to do some math to understand where exactly that child element ends up.

When using this modular scale it becomes much more apparent at a glance. The above values respectively become $font-up-4, $font-down-1, and $font-up-2. Now just do the basic math (4 - 1 + 2) and you know that child element will be equivalent to $font-up-5.

Additionally, as you’d expect with ems: this entire system would scale proportionately by changing the root font-size. You could change our html {font-size: 14px;} to 16px and every value would scale relative to that 16px. You could also decide to scale different components individually. If you decided you just wanted the post content to be based off of 16px, you could set .topic-post to 16px and all fonts would scale relative to their new parent, 16px.


With those gradations, might it possible to use “v” units and scale off a browser’s viewport?

I had started work on a font size theme but didn’t get far when the table got tossed. Got a github repo for what you have so far yet?


The point of this change is that we only need to change one line of CSS to bump up all the fonts, we will be trivially adjustable. Additionally we get to strip out a ton of pointless extra sizes and make it simpler to pick font sizes.

The font size theme you built absolutely exposed how painful our old font sizing system had.


It’s possible, but I think we’d lose some flexibility because viewport units are only relative to the viewport and not each other. If someone wanted to scale-up/down individual components they’d have to change every value within that component (or redefine all the variables used within). I was running into a similar limitation using REMs.

One thing we could do though, is change our html {font-size: 14px;} at different breakpoints, which would scale all the type in the app.

Got a github repo for what you have so far yet?

So far I’ve gone as far as making sure most of the font-sizes are in ems and shifting values to the scale I outlined above (except for font-awesome icons, which need to exist outside the system). That’s in this typography-2.0 branch:

I also have the scale in codepen if you want to try it out a bit:


By the way:
There is an small issue with the font size at the categories view. The font size of the subcategories are different from the categories on right column / topic list. It‘s pretty strange and new …


I‘ve noticed, that the font size is changing when I hold my iPad (mini 4) in portrait and landscape mode. In portrait mode, the size of the topic listing overview is (I guess) 1-2 times smaller, which makes it more difficult to read.

1 Like

Similarly to font-size we also have a large variety of line-height definitions, these are a mix of px, em, and unitless values.

It’s important to fix line-height here as well, because otherwise we’ll still have problems scaling font-size. For example, If you want to update a 14px (1em) font-size to 16px, and there’s a 14px line-height set, you now have a line-height that’s too small for your font-size.

That’s why it’s recommended that unitless line-height values are used, because your line-height will always be based on the font-size. With 14px font-size and line-height of 1, your line height will be 14px. Update the font-size to 16px and your line-height will be 16px. Unitless line-heights serve as multipliers of the font-size, not values.


New font system is live

This new font-size and line-height system has been merged into Discourse. These variables exist in our variables.scss file, and if you’re contributing to core you should refer to these (font-awesome icons are an exception).

If you’re nesting font-sizes, you can move up/down the scale using addition/subtraction. For example: If you have a parent div set to font-size: $font-up-6; and you set font-size: $font-down-2; within it, you’ll end up at font-size: $font-up-4 (so based on the root font size, that’s 1.7511em).

We also have 3 variables for line-heights now. These should generally be used to space lines of text, and not to create additional padding/margin on elements like buttons (we were using line-heights in some weird ways). Since these are unitless values, they’ll scale along with font size changes.

$font-up-6: 2.296em;
$font-up-5: 2em;
$font-up-4: 1.7511em;
$font-up-3: 1.5157em;
$font-up-2: 1.3195em;
$font-up-1: 1.1487em; 
$font-0: 1em; 
$font-down-1: .8706em; 
$font-down-2: .7579em; // Smallest size we use based on the 1em base
$font-down-3: .6599em;
$font-down-4: .5745em;
$font-down-5: .5em;
$font-down-6: .4355em;

$line-height-small: 1;
$line-height-medium: 1.2; // Headings or large text
$line-height-large: 1.4; // Normal or small text

Scaling fonts in themes

As a proof of concept, I created a “large fonts” theme available in the hamburger menu here on Meta. This theme consists of a single line of CSS: html {font-size: 16px !important;} (our default is 14px). You’ll see some small issues with margins in the header/nav (which should be easy to overcome in a full theme with a few additional lines of CSS), but overall scaling fonts should now be significantly easier.

You can also target individual sections of the UI and all the child elements will scale proportionately. For example, if you wanted to only scale the font size for posts, you could set .topic-post {font-size: 16px;}.


Looking good (not noticed anything glaringly different, which I guess is the point)


3 posts were merged into an existing topic: More formatting bugs with font size refactor

First of all, great to see some work being done on the fonts :+1:

I have an old theme with a gazillion font rules and fixes that I would gladly move to the new system. However, I noticed the new font system results in fractional font sizes and line heights. This brings back some bad memories from issues with font rendering on low dpi displays and sub pixel rendering. Is this intentional? Any way to (easily) stick to full pixel values? The variables cant be overridden from themes either, right?

What specific issues are you talking about, screenshots please.

1 Like

Of what, memories? I would like to increase the font size on my theme and use full pixel values unlike the default, is that not possible with the new system?

I hate proposing solutions if I can not visually see what problem it is your are trying to solve.

Screenshot please of big problems with DPI issue related to partial px values or it did not (or no longer does) happen on modern browsers :woozy_face:


There’s no easy way to change this unfortunately, you’d have to figure out a way to replace our SASS variables before they’re compiled (maybe a plugin could do it? I don’t think anyone has attempted it before).

We’ve been doing it this way for a full year now and haven’t had any issues with fractional values reported. Happy to fix any issues you may encounter due to it.


Hi, is this possible to change (override) these font system variables?

$font-up-6: 2.296em;
$font-up-5: 2em;
$font-up-4: 1.7511em;
$font-up-3: 1.5157em;
$font-up-2: 1.3195em;
$font-up-1: 1.1487em;
$font-0: 1em;
$font-down-1: .8706em;
$font-down-2: .7579em;
$font-down-3: .6599em;
$font-down-4: .5745em;
$font-down-5: .5em;
$font-down-6: .4355em;

I am adding this variables with custom values to CSS section, but there is no change?

It is not possible to override these, they’re already compiled in Discourse’s default CSS. You’d have to override the individual styles manually with your own values.