Section 5.2. Font Weights

5.2. Font Weights

Even though you may not realize it, you're already familiar with font weights; boldfaced text is a very common example of an increased font weight. CSS gives you more control over weights, at least in theory, with the property font-weight.



normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit

Initial value:


Applies to:

All elements



Computed value:

One of the numeric values (100, etc.), or one of the numeric values plus one of the relative values (bolder or lighter)

Generally speaking, the heavier a font weight becomes, the darker and "more bold" a font appears. There are a great many ways to label a heavy font face. For example, the font family known as Zurich has a number of variants, such as Zurich Bold, Zurich Black, Zurich UltraBlack, Zurich Light, and Zurich Regular. Each of these uses the same basic font, but each has a different weight.

So let's say that you want to use Zurich for a document, but you'd like to make use of all those different heaviness levels. You could refer to them directly through the font-family property, but you really shouldn't have to do that. Besides, it's no fun having to write a style sheet like this:

 h1 {font-family: 'Zurich UltraBlack', sans-serif;} h2 {font-family: 'Zurich Black', sans-serif;} h3 {font-family: 'Zurich Bold', sans-serif;} h4, p {font-family: Zurich, sans-serif;} small {font-family: 'Zurich Light', sans-serif;} 

Aside from the obvious tedium of writing such a style sheet, it works only if everyone has these fonts installed, and it's a pretty safe bet that most people don't. It would make far more sense to specify a single font family for the whole document and then assign different weights to various elements. You can do this, in theory, using the various values for the property font-weight. This is a fairly obvious font-weight declaration:

 b {font-weight: bold;} 

This declaration says, simply, that the b element should be displayed using a boldface font; or, to put it another way, a font that is heavier than the normal font for the document. This is what we're used to, of course, since b does cause text to be boldfaced.

However, what's really happening is that a heavier variant of the font is used for displaying a b element. Thus, if you have a paragraph displayed using Times, and part of it is boldfaced, then there are really two variants of the same font in use: Times and TimesBold. The regular text is displayed using Times, and the boldfaced text is displayed using TimesBold.

5.2.1. How Weights Work

To understand how a user agent determines the heaviness, or weight, of a given font variant, not to mention how weight is inherited, it's easiest to start by talking about the keywords 100 tHRough 900. These number keywords were defined to map to a relatively common feature of font design in which a font is given nine levels of weight. OpenType, for example, employs a numeric scale with nine values. If a font has these weight levels built-in, then the numbers are mapped directly to the predefined levels, with 100 as the lightest variant on the font and 900 as the heaviest.

In fact, there is no intrinsic weight in these numbers. The CSS specification says only that each number corresponds to a weight at least as heavy as the number that precedes it. Thus, 100, 200, 300, and 400 might all map to the same relatively lightweight variant; 500 and 600 could correspond to the same heavier font variant; and 700, 800, and 900 could all produce the same very heavy font variant. As long as no keyword corresponds to a variant that is lighter than the variant assigned to the previous keyword, everything will be all right.

As it happens, these numbers are defined to be equivalent to certain common variant names, not to mention other values for font-weight. 400 is defined to be equivalent to normal, and 700 corresponds to bold. The other numbers do not match up with any other values for font-weight, but they can correspond to common variant names. If there is a font variant labeled something such as "Normal," "Regular," "Roman," or "Book," then it is assigned to the number 400 and any variant with the label "Medium" is assigned to 500. However, if a variant labeled "Medium" is the only variant available, it is not assigned to 500 but instead to 400.

A user agent has to do even more work if there are fewer than nine weights in a given font family. In this case, it must fill in the gaps in a predetermined way:

  • If the value 500 is unassigned, it is given the same font weight as that assigned to 400.

  • If 300 is unassigned, it is given the next variant lighter than 400. If no lighter variant is available, 300 is assigned the same variant as 400. In this case, it will usually be "Normal" or "Medium." This method is also used for 200 and 100.

  • If 600 is unassigned, it is given the next variant darker than 400. If no darker variant is available, 600 is assigned the same variant as 500. This method is also used for 700, 800, and 900.

To illustrate this weighting scheme more clearly, let's look at three examples of font weight assignment. In the first example, assume that the font family Karrank% is an OpenType font, so it has nine weights already defined. In this case, the numbers are assigned to each level, and the keywords normal and bold are assigned to the numbers 400 and 700, respectively.

In our second example, consider the font family Zurich, which was discussed near the beginning of this section. Hypothetically, its variants might be assigned numeric values for font-weight, as shown in Table 5-1.

Table 5-1. Hypothetical weight assignments for a specific font family

Font face

Assigned keyword

Assigned number(s)

Zurich Light


100, 200, 300

Zurich Regular



Zurich Medium



Zurich Bold


600, 700

Zurich Black



Zurich UltraBlack



The first three number values are assigned to the lightest weight. The "Regular" face gets the keyword normal, as expected, and the number weight 400. Since there is a "Medium" font, it's assigned to the number 500. There is nothing to assign to 600, so it's mapped to the "Bold" font face, which is also the variant to which 700 and bold are assigned. Finally, 800 and 900 are assigned to the "Black" and "UltraBlack" variants, respectively. Note that this last assignment would happen only if those faces had the top two weight levels already assigned. Otherwise, the user agent might ignore them and assign 800 and 900 to the "Bold" face instead, or it might assign them both to one or the other of the "Black" variants.

Finally, let's consider a stripped-down version of Times. In Table 5-2, there are only two weight variants: "TimesRegular" and "TimesBold."

Table 5-2. Hypothetical weight assignments for "Times"

Font face

Assigned keyword

Assigned numbers



100, 200, 300, 400, 500



600, 700, 800, 900

The assignment of the keywords normal and bold is straightforward enough, of course. As for the numbers, 100 through 300 are assigned to the "Regular" face because there isn't a lighter face available. 400 is assigned to "Regular" as expected, but what about 500? It is assigned to the "Regular" (or normal) face because there isn't a "Medium" face available; thus, it is assigned the same font face as 400. As for the rest, 700 goes with bold as always, while 800 and 900, lacking a heavier face, are assigned to the next-lighter face, which is the "Bold" font face. Finally, 600 is assigned to the next-heavier face, which is, of course, the "Bold" face.

font-weight is inherited, so if you set a paragraph to be bold: {font-weight: bold;} 

then all of its children will inherit that boldness, as we see in Figure 5-4.

Figure 5-4. Inherited font-weight

This isn't unusual, but the situation gets interesting when you use the last two values we have to discuss: bolder and lighter. In general terms, these keywords have the effect you'd anticipate: they make text more or less bold compared to its parent's font weight. First, let's consider bolder.

5.2.2. Getting Bolder

If you set an element to have a weight of bolder, then the user agent first must determine what font-weight value was inherited from the parent element. It then selects the lowest number, which corresponds to a font weight darker than what was inherited. If none is available, then the user agent sets the element's font weight to the next numerical value, unless the value is already 900, in which case the weight remains at 900. Thus, you might encounter the following situations, illustrated in Figure 5-5:

 p {font-weight: normal;} p em {font-weight: bolder;}  /* results in bold text, evaluates to '700' */ h1 {font-weight: bold;} h1 b {font-weight: bolder;}  /* if no bolder face exists, evaluates to '800' */ div {font-weight: 100;} /* assume 'Light' face exists; see explanation */ div strong {font-weight: bolder;} /* results in normal text, weight '400' */ 

Figure 5-5. Text trying to be bolder

In the first example, the user agent moves up the weight ladder from normal to bold; in numeric terms, it jumps from 400 to 700. In the second example, H1 text is already set to bold. If there is no bolder face available, then the user agent sets the weight of b text within an h1 to 800, since that is the next step up from 700 (the numeric equivalent of bold). Since 800 is assigned to the same font face as 700, there is no visible difference between normal h1 text and boldfaced H1 text, but the weights are different nonetheless.

In the last example, paragraphs are set to be the lightest possible font weight, which we assume exists as a "Light" variant. Furthermore, the other faces in this font family are "Regular" and "Bold." Any em text within a paragraph will evaluate to normal since that is the next-heaviest face within the font family. However, what if the only faces in the font are "Regular" and "Bold"? In that case, the declarations would evaluate like this:

 /*   assume only two faces for this example: 'Regular' and 'Bold'   */ p {font-weight: 100;}   /* looks the same as 'normal' text */ p span {font-weight: bolder;}   /* maps to '700' */ 

As you can see, the weight 100 is assigned to the normal font face, but the value of font-weight is still 100. Thus, any span text that is descended from a p element will inherit the value of 100 and then evaluate to the next-heaviest face, which is the "Bold" face with a numerical weight of 700.

Let's take this one step further and add two more rules, plus some markup, to illustrate how all of this works (see Figure 5-6 for the results):

 /*   assume only two faces for this example: 'Regular' and 'Bold'   */ p {font-weight: 100;}   /* looks the same as 'normal' text */ p span {font-weight: 400;}   /* so does this */ strong {font-weight: bolder;}   /* even bolder than its parent */ strong b {font-weight: bolder;}   /*bolder still */ <p> This paragraph contains elements of increasing weight: there is a <span>span element that contains a <strong>strongly emphasized element and a <b>boldface element</b></strong></span>. </p> 

Figure 5-6. Moving up the weight scale

In the last two nested elements, the computed value of font-weight is increased because of the liberal use of the keyword bolder. If you were to replace the text in the paragraph with numbers representing the font-weight of each element, you would get the results shown here:

 <p> 100 <span> 400 <strong> 700 <b> 800 </b></strong></span>. </p> 

The first two weight increases are large because they represent jumps from 100 to 400 and from 400 to bold (700). From 700, there is no heavier face, so the user agent simply moves the value of font-weight one notch up the numeric scale (800). Furthermore, if you were to insert a strong element into the b element, it would come out like this:

 <p> 100 <span> 400 <strong> 700 <b> 800 <strong> 900 </strong></b></strong></span>. </p> 

If there were yet another b element inserted into the innermost strong element, its weight would also be 900, since font-weight can never be higher than 900. Assuming that there are only two font faces available, then the text would appear to be either Regular or Bold, as you can see in Figure 5-7:

 <p> regular <span> regular <strong> bold <b> bold <strong> bold </strong></b></strong></span>. </p> 

Figure 5-7. Visual weight, with descriptors

5.2.3. Lightening Weights

As you might expect, lighter works in just the same way, except it causes the user agent to move down the weight scale instead of up. With a quick modification of the previous example, you can see this very clearly:

 /*   assume only two faces for this example: 'Regular' and 'Bold'   */ p {font-weight: 900;}   /* as bold as possible, which will look 'bold' */ p span {font-weight: 700;}   /* this will also be bold */ strong {font-weight: lighter;}   /* lighter than its parent */ b {font-weight: lighter;}   /* lighter still */ <p> 900 <span> 700 <strong> 400 <b> 300 <strong> 200 </strong></b></strong></span>. </p> <!-- ...or, to put it another way... --> <p> bold <span> bold <strong> regular <b> regular <strong> regular </strong></b></strong></span>. </p> 

Ignoring the fact that this would be entirely counterintuitive, what you see in Figure 5-8 is that the main paragraph text has a weight of 900. When the strong text is set to be lighter, it evaluates to the next-lighter face, which is the regular face, or 400 (the same as normal) on the numeric scale. The next step down is to 300, which is the same as normal since no lighter faces exist. From there, the user agent can reduce the weight only one numeric step at a time until it reaches 100 (which it doesn't do in the example). The second paragraph shows which text will be bold and which will be regular.

Figure 5-8. Making text lighter

CSS(c) The Definitive Guide
CSS: The Definitive Guide
ISBN: 0596527330
EAN: 2147483647
Year: 2007
Pages: 130
Authors: Eric A. Meyer

Similar book on Amazon © 2008-2017.
If you may any questions please contact us: