Having multiple font files for a single font can lead to a messy css if you don't know how to use them all together as a single font-family, using the full potential of the @font-face
css declaration.
When implementing the design of a website we often have to use different files for different font weights (light, bold) and font styles (italic, oblique). Some custom-made fonts don't contain all the variations of all the characters and the reasons for this are a topic for another article.
If you are like me, you're just a developer implementing the design that someone else has already created. The designer wants you to use several files with different font characteristics of a single font. For example:
Roboto-Regular.woff
Roboto-Light.woff
Roboto-Semibold.woff
Roboto-Bold.woff
Roboto-Italic.woff
Roboto-BoldItalic.woff
Initial approach (not recommended)
When I first saw this, I was taunted by the complexity that this would bring into the css implementation. If I use only a single font (for example "Roboto-Regular") for the entire website and set the font-weight
property to 600 (semibold) - the font looks different than it does in the design I'm given. That's because the browser tries to use the "Roboto-Regular" font with font-weight: 600;
and it fails to produce a decent result. That brings me to an implementation of this sort:
@font-face {
font-family: 'Roboto-Regular';
src: url(fonts/Roboto-Regular.woff) format('woff');
}
@font-face {
font-family: 'Roboto-SemiBold';
src: url(fonts/Roboto-SemiBold.woff) format('woff');
}
@font-face {
font-family: 'Roboto-Bold';
src: url(fonts/Roboo-Bold.woff) format('woff');
}
body {
font-family: 'Roboto-Regular';
}
And then whenever I want some text to have a font-weight of 600 (semibold) I would have to write:
p {
font-family: 'Roboto-Semibold';
}
instead of what everyone would expect:
p {
font-weight: 600;
}
This proves difficult to read, troublesome to use with libraries and a pain to implement. Overall it's a bad solution for this case.
Solution (recommended)
The better solution is to use the full potential of the @font-face
rule. It describes the styles that an element should have in order for this @font-face
rule to be used. Let's call those characteristics in the @font-face
"guards". The @font-face
itself has a lot of different guards that can be checked before a font is used for some purpose.
@font-face {
/* Essential deinitions. Without one them the font-face is considered invalid */
font-family: <name>;
src: <local/url/guards>;
/*
"Guard" definitions.
They define the cases when the current font-face should be used.
They can all be omitted in a font-face definition
*/
unicode-range: <range of characters for which the font should be used>;
font-variant:
normal | [ <east-asian-variant-values> || <east-asian-width-values> || ruby ];
font-feature-settings: normal | <feature-tag-value>;
font-stretch:
normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded;
font-weight:
normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
font-style: normal | italic | oblique;
}
Using the font-face guards, we can improve our css from above to be:
@font-face {
font-family: 'Roboto';
src: url(fonts/Roboto-Regular.woff) format('woff');
font-style: normal;
font-weight: 400;
}
@font-face {
font-family: 'Roboto';
src: url(fonts/Roboto-SemiBold.woff) format('woff');
font-style: normal;
font-weight: 600;
}
@font-face {
font-family: 'Roboto';
src: url(fonts/Roboto-Italic.woff) format('woff');
font-style: italic;
font-weight: 400;
}
@font-face {
font-family: 'Roboto';
src: url(fonts/Roboto-Bold.woff) format('woff');
font-style: normal;
font-weight: 700;
}
@font-face {
font-family: 'Roboto';
src: url(fonts/Roboto-BoldItalic.woff) format('woff');
font-style: italic;
font-weight: 700;
}
body {
font-family: Roboto;
}
Now, when we want a certain part of our website to use the "Roboto-SemiBold" font file - we can still use the "Roboto" font family (like defined in the body
element above) and only change the font-weight
of that element to 600. This will force the browser to use the definition we gave of the font-face with font-weight: 600
. Thus our code becomes something like this:
p {
font-weight: 600;
}
instead of
/* Not recommended */
p {
font-family: 'Roboto-SemiBold';
}
Further reading
The same works for using different font-files for different font-stylefont-stretch
and even using a font file for different ranges of characters. You can use some fonts only for certain characters or unicode character ranges (like use them only for cyrlic or only for latin). This is possible by using the unicode-range
guard. More on that in a future article, or in this link.