Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 32619: clarify font-weight descriptor #32853

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
129 changes: 113 additions & 16 deletions files/en-us/web/css/@font-face/font-weight/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ browser-compat: css.at-rules.font-face.font-weight

{{CSSRef}}

The **`font-weight`** CSS descriptor allows authors to specify font weights for the fonts specified in the {{cssxref("@font-face")}} at-rule. The {{cssxref("font-weight")}} property can separately be used to set how thick or thin characters in text should be displayed.
The **`font-weight`** CSS descriptor enables authors to specify a single font weight, or a range of font weights, for the font specified in a {{cssxref("@font-face")}} at-rule. This is then used by the browser to select the appropriate font when a CSS rule sets the desired weight of a font.

For a particular font family, authors can download various font faces which correspond to the different styles of the same font family, and then use the `font-weight` descriptor to explicitly specify the font face's weights. The values for the CSS descriptor is same as that of its corresponding font property.
Unless it contains a [variable font](/en-US/docs/Web/CSS/CSS_fonts/Variable_fonts_guide), a single font file contains characters from a font family in a specific weight and style: for example, "Helvetica bold italic". Typically, a developer will want to use fonts from a single font family in a range of different weights. To accomplish this, you can define multiple {{cssxref("@font-face")}} at-rules for the same family, one for each weight, and set the `font-weight` descriptor to define the weight range for which that particular font file will be used. When CSS rules set a font weight by setting the {{cssxref("font-weight")}} property or the {{cssxref("font")}} shorthand property, the appropriate font will then be used.
estelle marked this conversation as resolved.
Show resolved Hide resolved

There are generally limited weights available for a particular font family. When a specified weight doesn't exist, a nearby weight is used. Fonts lacking bold typeface are often synthesized by the user agent. To prevent this, use the {{cssxref('font-synthesis')}} shorthand property.
If a font file contains a variable font, it may support a range of font weights. To reflect this, the `font-weight` descriptor can specify the range of font weights for which the font should be used as a space-separated pair of font-weight values.

## Syntax

Expand All @@ -21,26 +21,28 @@ font-weight: normal;
font-weight: bold;
font-weight: 400;

/* Multiple Values */
/* Defining a range */
font-weight: normal bold;
font-weight: 300 500;
```

The `font-weight` property is described using any one of the values listed below.

### Values

The syntax of the `font-weight` descriptor takes one of the following forms:

- The keyword `auto`.
- A single `<font-weight-absolute>` value.
- A pair of `<font-weight-absolute>` values, separated by a space.

Each `<font-weight-absolute>` may be any one of the following:

- `normal`
- : Normal font weight. Same as `400`.
- `bold`
- : Bold font weight. Same as `700`.
- `<number>`
- : A {{cssxref("&lt;number&gt;")}} value between 1 and 1000, inclusive. Higher numbers represent weights that are bolder than (or as bold as) lower numbers. Certain commonly used values correspond to common weight names, as described in the [Common weight name mapping](#common_weight_name_mapping) section below.

In earlier versions of the `font-weight` specification, the property accepts only keyword values and the numeric values 100, 200, 300, 400, 500, 600, 700, 800, and 900; non-variable fonts can only really make use of these set values, although fine-grained values (e.g. 451) will be translated to one of these values for non-variable fonts.

CSS Fonts Level 4 extends the syntax to accept any number between 1 and 1000, inclusive, and introduces [Variable fonts](#variable_fonts), which can make use of this much finer-grained range of font weights.

### Common weight name mapping

The numerical values `100` to `900` roughly correspond to the following common weight names:
Expand Down Expand Up @@ -80,20 +82,115 @@ People experiencing low vision conditions may have difficulty reading text set w

## Examples

### Setting normal font weight in a @font-face rule
### Selecting normal and bold fonts

In this example we include two fonts, one normal weight, one bold weight, from the ["Fira Sans"](https://fonts.google.com/specimen/Fira+Sans) font family using two `@font-face` at rules. We set `font-weight` descriptors to match the weight of the fonts.

The following finds a local Open Sans font or imports it, and allows using the font for normal font weights.
After this, CSS rules can select the normal or the bold font for the "Fira Sans" family just by setting the {{cssxref("font-weight")}} property. Note that the {{htmlelement("strong")}} HTML element also selects the bold font, because by default `<strong>` elements use a bold font.

#### HTML

```html
<p class="one">Fira Sans, normal weight paragraph</p>
<p class="two">Fira Sans, bold weight paragraph</p>
<strong>Fira Sans, default weight &lt;strong&gt; element</strong>
estelle marked this conversation as resolved.
Show resolved Hide resolved
```

#### CSS

```css
@font-face {
font-family: "Open Sans";
src:
local("Open Sans") format("woff2"),
url("/fonts/OpenSans-Regular-webfont.woff") format("woff");
font-family: "Fira Sans";
font-weight: normal;
src: url("https://mdn.github.io/shared-assets/fonts/FiraSans-Regular.woff2");
}

@font-face {
font-family: "Fira Sans";
font-weight: bold;
src: url("https://mdn.github.io/shared-assets/fonts/FiraSans-Bold.woff2");
}

body {
font-family: "Fira Sans", serif;
font-size: 2rem;
}

p.one {
font-weight: normal;
}

p.two {
font-weight: bold;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works, but it's the default action expected of "font-weight: bold;". Should we invert the font calls, so Karantina-Bold is displayed for normal and Karantina for bold? Or something similar to show this really makes a difference?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this comment.

it's the default action expected of "font-weight: bold;"

I'm not sure what "the default action" means here. Like, if you don't set the font-weight descriptor, like this:

@font-face {
  font-family: "Karantina";
  src: url("Karantina-Regular.woff2");
}

@font-face {
  font-family: "Karantina";
  src: url("Karantina-Bold.woff2");
}

body {
  font-family: "Karantina", serif;
  font-size: 3rem;
}

p.one {
  font-weight: normal;
}

p.two {
  font-weight: bold;
}

...then both paras and the <strong> will select "Karantina-Bold" because that's matched last (I think). The browser will also apply synthetic boldification to para 2 and the <strong>:

Screen Shot 2024-04-03 at 8 03 40 PM

It's only because we've set the font-weight descriptor that:

  • para 1 selects "Karantina-Regular",
  • para 2 and the <strong> select "Karantina-Bold" don't apply synthetic boldification
    ... and we get proper typography:
Screen Shot 2024-04-03 at 8 05 16 PM

That's what this example is showing: by setting the font-weight descriptor, you enable a rule to select the appropriate font file by setting the font-weight property.

At least such is my understanding.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything you wrote is correct. The issue is that the user will not be able to see a difference between a synthetic bold and the use of the actual bold font.

I found this old example I wrote that barely works, but explains what I mean. At https://estelle.github.io/CSS/fonts/index.html#slide60 (slide 60 if the presentation doesn't actually move forward), if you change the font-weight in the p.fwd block to 700, you'll note the font family changes. The deck is old, and i had all the other fonts on my local machine when i did the presentation, so only the boldest font will work on your device. In that CSS, all the @font declarations are using the same font-family descriptor, but include different font-weight values and import complete different fonts. That was the user can see that a different font file is being used when the font-weight leads to different font-files used to render content. This is obviously not something one would do in production, but it enables the learner to really see what is going on.

In the current example on this page, the example will still be bold (or light) if the fonts don't even load. Yes, the second paragraph and the <strong> select "Karantina-Bold" and don't apply a synthetic a bold because we say so, but is it really just applying a synthetic bold? If we use drastically different fonts for normal v. bold in our @font src descriptor, the user will definitely see the effect. My suggestion was to invert bold and normal to show the difference, but drastically different fonts would be better (as it would be less confusing that "messing up" and explaining it)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this example should show the actual proper common usage of the font-weight descriptor to support multiple fonts in the same family, which is what it currently does. It implies "this is a good-practice way to use font-weight, if you're not using variable fonts". That's why I don't think we should change it to show something unrealistic, even if it is more illustrative.

I do agree that the counterfactual is not that clear, and that font synthesis makes the story more complicated. It might help to:

(a) find a font family that has a clearer differentiation between bold and normal weight
(b) maybe talk about the counterfactual (and even show it in the example) to explain what is happening (and that it is in fact broken)

That would make the example quite complex. I think one underlying problem here is that a lot of this explanation would go into a guide page, and because we don't have one, it is having to go here instead.

But I do think it is important for the first example here to show an actual good practice usage. Otherwise people have to infer it from unrealistic examples, and that's also putting a burden on them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All valid points. We really do need a font guide!

We can leave as is, but I did think of other options. Sharing in case you want to include one of them:

  1. Duplicating the first example as a second example, and just inverting the bold / normal descriptors, with something like "This example "accidentally" inverts the font-weight descriptors, leading to a bold font being rendered when the font-weight property is normal and a normal font is rendered when the property is bold.

  2. including 3 katerina fonts, serving 'light' up to 500, regular from 501 to 700, and bold 701 and above (though this would be for the numeric example after this one)

  3. in the numeric example, leaving gaps, so fallback font-family is used below 200 and above 800 or something similar.

}
```

#### Result

{{embedlivesample("Selecting normal and bold fonts", "", 300)}}

### Setting a range for a variable font

In this example we include a variable font, ["League Mono"](https://www.theleagueofmoveabletype.com/league-mono), using a single `@font-face` at-rule. We've used a `font-weight: 300 700` value to effectively limit the range of weights that are available. If a CSS rule uses our "League Mono" font, then if it specifies a weight outside this range the weight it gets is clamped to the range.

To show the effect of this we've included another font using "League Mono" that does not set the `font-weight` descriptor, and we've called this "League Mono-complete".

#### HTML

```html
<p class="one">League Mono-complete, font-weight 200</p>
<p class="two">League Mono, font-weight 400</p>
<p class="three">League Mono, font-weight 600</p>
<p class="four">League Mono-complete, font-weight 800</p>
```

#### CSS

```css
@font-face {
font-family: "League Mono";
src: url("https://mdn.github.io/shared-assets/fonts/LeagueMono-VF.ttf");
font-weight: 300 700;
}

@font-face {
estelle marked this conversation as resolved.
Show resolved Hide resolved
font-family: "League Mono-complete";
src: url("https://mdn.github.io/shared-assets/fonts/LeagueMono-VF.ttf");
estelle marked this conversation as resolved.
Show resolved Hide resolved
}

p {
font-family: "League Mono", "League Mono-complete", serif;
estelle marked this conversation as resolved.
Show resolved Hide resolved
font-size: 1.5rem;
}

p.one {
font-weight: 200;
}

p.two {
font-weight: 400;
}

p.three {
font-weight: 600;
}

p.four {
font-weight: 800;
}
```

#### Result

The result of this is:

- Setting the `font-weight` property to `100` for "League Mono" gets a weight of 300.
- Setting the `font-weight` property to `900` for "League Mono" gets a weight of 700.
- Setting the `font-weight` property to `100` for "League Mono-complete" gets a weight of 100.
- Setting the `font-weight` property to `900` for "League Mono-complete" gets a weight of 900.
estelle marked this conversation as resolved.
Show resolved Hide resolved

{{embedlivesample("Setting a range for a variable font", "", "400")}}

## Specifications

{{Specifications}}
Expand Down
Loading