Firefox’s `bolder` Default is a Problem for Variable Fonts

Variable fonts make it easy to create a large set of font styles from a single font file. Unfortunately, the default rendering of the <b> and <strong> elements in browsers today is not very compatible with the wide range of font-weight values enabled by variable fonts.

Browsers disagree on the default font-weight of <b>

The purpose of the <b> and <strong> elements is to draw attention to a specific word or span of text on the page. Browsers make these elements stand out by increasing their font-weight. This works well under normal conditions. For example, MDN Web Docs uses <b> in a few places in the “Found a problem?” card at the bottom of each page.

Screenshot of an MDN article with red arrows pointing at instances of bolded words on the page.

Things become more complicated when the text on the page has a custom font-weight. The default weight of text is 400, but the font-weight property accepts any number between 1 and 1000 (inclusive). Let’s take a look at how Chrome and Firefox render text wrapped in <b> by default depending on the font-weight of the surrounding text.

View on CodePen

Chrome and Firefox disagree on the default rendering of <b> elements. Chrome uses a constant font-weight of 700 (Safari behaves the same), while Firefox chooses between three values (400, 700, and 900) depending on the font-weight of the surrounding text.

Where is this difference coming from?

As you might have guessed, Chrome and Firefox use different font-weight values for the <b> and <strong> elements in their user agent stylesheets.

/* Chrome and Safari’s user agent stylesheet */
strong, b { font-weight: bold;
} /* Firefox’s user agent stylesheet */
strong, b { font-weight: bolder;
}

The bold and bolder values are specified in the CSS Fonts module; bold is equivalent to 700, while bolder is a relative weight that is calculated as follows:

If the outer text has a font-weight of… the bolder keyword computes to…
1 to 349 400
350 to 549 700
550 to 899 900
900 to 1000 No change (same value as outer text)

Chrome and Firefox disagree on the default rendering of <b>, but which browser follows the standards more closely? The font-weight property itself is defined in the CSS Fonts module, but the suggested font-weight values for different HTML elements are located in the Rendering section of the HTML Standard.

/* The HTML Standard suggests the following user agent style */
strong, b { font-weight: bolder;
}

The HTML Standard started suggesting bolder instead of bold all the way back in 2012. As of today, only Firefox follows this recommendation. Chrome and Safari have not made the switch to bolder. Because of this inconsistency, the popular Normalize base stylesheet has a CSS rule that enforces bolder across browsers.

Which of the two defaults is better?

There are two different defaults in browsers, and Firefox’s default matches the standard. So, should Chrome align with Firefox, or is Chrome’s default the better one? Let’s take another look at the default rendering of the <b> element.

View on CodePen

Each of the two defaults has a weak spot: Chrome’s bold default breaks down at higher font-weight values (around 700), while Firefox’s bolder default has a problem with lower font-weight values (around 300).

In the worst-case scenario for Firefox, text wrapped in <b> becomes virtually indiscernible. The following screenshot shows text at a font-weight of 349 in Firefox. Can you spot the single word that is wrapped in <b>? Firefox renders this element at a default font-weight of 400, which is an increase of only 51 points.

Three paragraphs of text about English scientist Tim Berners-Lee. All of the text appears to be the same font weight.

(View on CodePen)

The takeaway

If you use thin fonts or variable fonts at font-weight values below 350, be aware that the <b> and <strong> elements may not always be discernible in Firefox by default. In this case, it is probably a good idea to manually define a custom font-weight for <b> and <strong> instead of relying on the browser’s sub-optimal default, which insufficiently increases the font-weight of these elements.

/* Defining the regular and bold font-weight at the same time */ body { font-weight: 340;
} b,
strong { font-weight: 620;
}

The bolder value is outdated and doesn’t work well with variable fonts. Ideally, text wrapped in <b> should be easy to spot regardless of the font-weight of the surrounding text. Browsers could achieve that by always increasing the font-weight by the same or a similar amount.

On that note, there is a discussion in the CSS Working Group about allowing percentages in font-weight in the same manner as in font-size. Lea Verou writes:

A far more common use case is when we want a bolder or lighter stroke than the surrounding text, in a way that’s agnostic to the weight of the surrounding text.

/* Increasing font-size by 100% */
h1 { font-size: 200%;
} /* PROPOSAL - Increasing font-weight by 50% */
strong, b { font-weight: 150%;
}

Taking variable fonts into account, a value like 150% would probably be a better default than the existing bold/bolder defaults in browsers today.