- July 17, 2021
- Posted by: team SOUTECH
- Category: Blog, Professional Website Design Free Training, Responsive Web Design, Web Development Training, Website Design Service Abuja, Website Design Training
Typography on the web has come on tremendously in the last few years. Where once it was necessary to include a slew of different file formats, things have pretty much settled on .woff and the newer .woff2. In addition, we have more control over the particulars of our fonts in CSS and new variable fonts are popping up on a monthly basis.
If some of that introduction was lost on you, fear not. Let’s try to get through the current state of the art in web typography.
First, however, let’s talk about system fonts as they represent the best performing web typography choice you can opt for
System fonts
Each operating system has its own set of fonts that come preinstalled. However, aside from a few exceptions, there aren’t many fonts you can rely upon to be installed on every device a user might view your site with.
Subsequently, we’ve grown accustomed to writing font “stacks,” which enable us to write a font “wish list” for the browser. For example:
font-family: -apple-system, BlinkMacSystemFont, Roboto, Ubuntu, ‘Segoe UI’, ‘Helvetica Neue’, Arial, sans-serif;
The browser reads this declaration and goes left to right until it finds a font it has available and then chooses that to render the associated text.
In our example system font stack here, macOS users will get San Francisco or Helvetica (-apple-system tells Safari to pick San Francisco and BlinkMacSystemFont tells Chrome to use Helvetica), Android will get “Roboto,” the popular Ubuntu Linux distribution will get “Ubuntu,” Windows users will see “Segoe UI,” and then we have some last ditch attempts to get something nice with “Helvetica Neue” or “Arial.” If all else fails, we tell the browser to use any sans-serif font it has.
Some font names contain whitespace, so it is necessary to surround those strings with single or double quotes. You can see in our previous example that both “Segoe UI” and “Helvetica Neue” are written this way.
For a lot of situations, using system fonts is a compelling choice. There is zero network overhead and you’ll never have to worry about fonts not loading or seeing unsightly jumps on the page as one font is replaced with another.
The tradeoff is that with system fonts, you can never be entirely sure how your text is being rendered on the user’s device. If specific typography is crucial to the project at hand, you’ll want to look at web fonts with @font-face.
The @font-face CSS rule
The @font-face CSS rule has been around since CSS2 (but was subsequently absent in CSS 2.1). It was even supported partially by Internet Explorer 4 (no, really)! So, what’s it doing here, when we’re supposed to be talking about the latest CSS?
Well, as it turns out, @font-face was reintroduced for the CSS Fonts Module (http://www.w3.org/TR/css3-fonts). Due to the historic legal quagmire of using fonts on the web, it took years to gain traction as the de facto solution for web typography.
Like anything on the web that involves assets, in the beginning, there was no single file format for font delivery. The Embedded OpenType (files with an .eot extension) font was Internet Explorer’s, and not anyone else’s, preferred choice. Others favored the more common TrueType (the.ttf file extension), while there was also Scalable Vector Graphics (.svg) and then the Web Open Font Format (the.woff / .woff2 extension).
Thankfully, as of 2020, you really only need to consider WOFF (Web Open Font Format), although there are two types: WOFF and WOFF2. Where a user can use WOFF2, that will always be preferable as it is simply a more efficient way of compressing the font information.
However, the good news is that adding each custom font format for every browser is easy. Let’s see how!
Implementing web fonts with @font-face
There are a number of online font services for getting beautiful typefaces onto the web. Google Fonts and Adobe Fonts are probably the two most popular. They each have their own variation of the required syntax for getting their fonts onto your websites. However, as it’s not always possible or preferable to use an online font provider, we will look at how to do it for ourselves.
For this exercise, I’m going to use “Inter” by Rasmus Andersson. It’s the font used for the majority of the https://rwd.education website. Not only that, it’s also what’s known as a “variable” font.
Before we look at variable fonts, let’s look at the kind of web fonts that you will likely spend the majority of your time dealing with. If you grab the “Inter” font from https://rsms.me/inter/, you will have both the standard and variable fonts at your disposal.
If you can, download a “subset” of your font, specific to the language you intend to use. For example, if you are not going to be using Cyrillic or Greek characters, why include them? The resultant file size will be much smaller as it won’t contain glyphs for languages you have no intention of using. You can often choose character sets when you are buying a font, but for an open source version, there are a growing number of services and utilities that can subset a font for you.
Having downloaded the “Inter” font, a look inside the ZIP file reveals folders of the different files available. I’m choosing the Inter-Regular.woff2 and Inter-Regular.woff files for our example.
To make a web font available for use in our CSS, we use the @font-face at-rule. This lets us provide a name for the font that we can then reference and also tells the browser where to go and fetch this file from. Let’s look at the syntax:
</pre> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">@font-face {</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-family: 'InterRegular';</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> src: url('Inter-Regular.woff2') format('woff2'),</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">url('Inter-Regular.woff') format('woff');</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-weight: normal;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-style: normal;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-display: fallback;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p> <pre>
Inside the @font-face braces, we give our font the “InterRegular” name. I could have called it “FlyingBanana” had I wanted; it wouldn’t affect anything other than I would then need to reference this font with that name when I wanted to use it. For example:
</pre> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">.hero-Image {</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-family: 'FlyingBanana', sans-serif;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p> <pre>
So, know that you can do this, but it makes sense to use a name similar to the font you are expecting to see!
You can then see two successive url() and format() sections within our src property. Each pair of these separated with a comma. As we noted previously, .woff2 is always our preference, as it is a better compressed version of the same font, so we list that first. As long as the browser can understand .woff2 and download the file, it will do so. If, however, the browser can’t find that file, or can’t understand .woff2, it will download the .woff file listed afterward.
Now, although this block of code is great for fans of copy and paste, it’s important to pay attention to the paths the fonts are stored in. For example, if we were to place fonts in a folder inventively called fonts on the same level as a css folder, we would need to amend our paths. So, our @font-face block would become:
</pre> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">@font-face {</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-family: 'InterRegular';</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> src: url('../fonts/Inter-Regular.woff2') format('woff2'),</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">url('../fonts/Inter-Regular.woff') format('woff');</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-weight: normal;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-style: normal;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-display: fallback;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p> <pre>
Optimizing font loading with font-display
If your main font is a web font, it’s a good idea to request the file up front by loading it with a link in the head section of your HTML with the rel attribute value as preload. For example:
</pre> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"><link</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> rel="preload"</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> href="fonts/inter.var.woff2"</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> as="font"</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> type="font/woff2"</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> crossorigin</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">/></p> <pre>
You can read more about this font optimization technique here: https://developers.google.com/web/fundamentals/performance/resource-prioritization.
Adding a link with rel=”preload” added in this way triggers a request for the web font early in the critical rendering path, without having to wait for the CSSOM to be created. While this technique is recommended by Google, even if other browsers don’t do the same, it is unlikely to do any harm. It’s only worth doing this for the .woff2 file. Browsers that support .woff2 also support the preloadvalue in therel attribute.
We can make further optimizations with web fonts by making use of the font-display property.
font-display
For browsers that support it, we can also make use of the relatively new font-display property of CSS (older browsers ignore it):
font-display: fallback;
You can also see this property being used in the previous examples. It provides some control over how fonts should get displayed.
The fallback value we have provided sets an extremely short “block” period and a short “swap” period.
To understand what terms like “block” and “swap” mean in this context, we need to consider what the browser does in terms of displaying fonts. I’m talking generically here, but the concepts work for our needs.
Imagine a browser loading our web page in which we have specified a web font for our text. The browser already has the HTML and is parsing the CSS, and learns it needs to download a font in order to display the text it has as intended. Before it draws any text to screen, it hangs on, waiting for the web font so it can paint the text onto the page as needed. This delay is referred to as a “FOIT,” standing for “Flash of Invisible Text.”
As soon as the font arrives, the browser parses it and paints the text to the screen accordingly.
The hope is that this delay is imperceptible. Where it is not, there are two schools of thought on how best to handle things.
One option is to wait for the font to be downloaded, usually for up to a few seconds but sometimes indefinitely; Safari is the most famous proponent of this option.
The second option is to render the text with a system font initially and then replace the font with the correct font when the browser has it.
This redraw of text from system font to actual intended font is known as a “Flash of Unstyled Text,” or “FOUT” for short.
All the font-display setting does is allow us some control over what we would like to see happen.
The possible values are:
- auto: Whatever the browser determines is most appropriate.
- block: Get a white screen for up to 3 seconds (but the delay is ultimately at the browser’s discretion) and then the actual font can replace any system displayed one at any future point.
- swap: There is a very short blocking period (100 ms is the recommended amount) to let the web font load; otherwise, a system font shows and the web font can be swapped in whenever it is available.
- fallback: This option prevents a web font from replacing a system font if a set amount of time has passed (3 seconds is the recommendation). This option blocks for around 100 ms initially and allows a swap for up to 3 seconds, but after that, if the web font subsequently arrives, it doesn’t get applied.
- optional: Here, the browser allows a very short duration for the web font to load (100 ms) but no swap period. The result of this is that the browser has the option of cancelling the font download if it hasn’t arrived, or if it has, using it for subsequent page loads.
You can read the specification on this property here: https://www.w3.org/TR/css-fonts-4/#font-display-desc.
There are plenty of other font-related properties and values specified in the CSS Font Module Level 4 specification, but font-display is currently the widest implemented and has the most direct relevance to responsive web designs and performance.
So far, we have looked at how to get font files into our project and even considered how best to deal with them from a performance point of view.
However, the most recent development in web fonts, and probably the one that has most developers excited, is “variable” fonts. What new witchery is this? I hear you cry. Let’s find out.
Variable fonts
As I write this in 2020, variable fonts are just gaining decent traction. There is a W3C specification and they are supported in the latest browsers. However, as support is limited to the latest browser versions and operating systems, while we will cover variable fonts here, be aware that the reality for the next few years is that you will need to consider fallback scenarios.
A “normal” font contains the information and glyphs for one variation of a typeface; the regular version of Roboto, for example. By comparison, a variable font, in a single file would contain everything needed for every variation of Roboto. Bold, Italic, Thin, Black, Medium, and more besides!
This new devilry is not without consequence. A variable version of a font is usually considerably larger in file size terms than a “normal” version. However, it can still make sense when you are making heavy use of a single typeface.
Caveats aside, let’s look at what we can do with a variable font.
font-face changes
I’m working with the “Inter” font we used before, but instead using the variable version. First, let’s consider how we tell the browser we are working with a variable font in the first place. It’s the @font-face syntax again but with a few changes:
</pre> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">@font-face {</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-family: 'Inter-V';</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> src: url('fonts/inter.var.woff2') format('woff2-variations');</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-weight: 100 900;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-style: oblique 0deg 10deg;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-display: fallback;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p> <pre>
The first thing to note is the format. We are setting this to woff2-variations to tell the browser this is a font file that makes use of variations.
The next thing to keep in mind is that we are using a range for font-weight. The two-word value syntax we are using here is only understood by browsers that understand variable fonts. It is a way of telling the browser the range weights this font can use. While font-weight has a range limit of 0-999, other properties may have a different range. Others still simply accept a value of 1 or 0.
Another thing to remember is that we have font-style, which is also being provided with a multiple value syntax. The oblique keyword tells the browser the next values relate to how oblique the font can be, and the two values after that define the range. Be aware that although the range here is positive, you can pass in negative values. We will see that in use momentarily.
Finally, note that we have used the font-display property here to tell the browser how we want to handle the loading and display of this font, but that is no different than non-variable fonts.
Using a variable font
Variable fonts use what’s termed a “variation axis.”
A variation axis is just a way of defining two points at either end of a scale. You can then choose any point along the scale to display your font. The scale doesn’t need to be vast; in fact, it can be as simple as “on” or “off” (not much of a scale, I know).
Variation axes are subdivided into two groups: registered and custom.
Registered axis
Registered axes are the most popular ones, which the specification has deemed worthy of their own CSS property:
- Weight: How heavy the text appears; for example, font-weight: 200.
- Width: How narrow (condensed) or wide the text appears; for example, font-stretch: 110%.
- Italic: Whether the font is being displayed as italic or not; for example, font-style:italic.
- Slant: Don’t confuse this with italic. This simply alters the angle of the text; it doesn’t substitute any glyphs; for example, font-style: oblique 4deg.
- Optical-size: This is the only one of the registered axes that has required a new font property. Using font-optical-sizing lets you alter, yes, you guessed it, the optical sizing. But what is that? It’s the practice of altering a glyph based upon the size it is displayed at to aid clarity. This means the same glyph displayed at a large size might enjoy thinner stems, for example.
The values you choose to use with these properties should fall within the capabilities of the variable font you are using. For example, there isn’t much point specifying a font weight of 999 if the font you are using can only go up to 600.
There is also a low-level property that lets you bundle up your variable font settings into a single property/value combination:
font-variation-settings: ‘wght’ 300, ‘slnt’ -4;
Here, we have set font-weight to 300 and the angle of the slant to -4. However, the specification offers the following cautionary advice:
When possible, authors should generally use the other properties related to font variations (such as font-optical-sizing), and only use this property for special cases where its use is the only way of accessing a particular infrequently used font variation. For example, it is preferable to use font-weight: 700 rather than font-variation-settings: “wght” 700.
I’m not really sure why this advice is given. The specification doesn’t explain the rationale. Hopefully, this detail will be added when the specification is complete. You can find the current version here: https://drafts.csswg.org/css-fonts-4/.
Font variation properties can be animated and transitioned, which can make for some fantastic effects!
Having covered the registered axis group, let’s briefly take a look at the custom axis group.
Custom axis
Variable fonts can include their own axis. For example, the “FS Pimlico Glow VF” font has a “glow” axis. You can amend that like this:
font-variation-settings: ‘GLOW’ 500;
Notice how this custom axis is written in uppercase; that is, ‘GLOW’? That’s how to determine the difference between a registered and custom axis in variable font settings.
If your head isn’t already hurting from the seemingly endless possibilities, I also need to tell you about font features, which are sort of similar to the two different axes we just looked at. Don’t worry; it will make sense shortly.
Font features
Variable fonts can also include their own “features.” These features can be literally anything the font designer decides to dream up! Take a look at the choices for Inter:
All of those “features” are settings that can be turned on with CSS. You can play about with these settings for yourself here: https://rsms.me/inter/lab/?varfont=1.
When we want to apply these custom features, we make use of the font-feature-settings property. This works very similarly to the font-variation-settings syntax. For example, to switch on “slashed zeroes,” we can do this:
font-feature-settings: ‘zero’;
This “slashed zeroes” option is a binary choice, so it is not necessary to write ‘zero’ 1. However, if we wanted to toggle this setting off further into our styles, we could write:
font-feature-settings: ‘zero’ 0;
When you want to apply multiple font-feature settings, you can comma-separate them. So, if we wanted to have “Lowercase L with tail” and “Uppercase i with serif,” we could write this:
font-feature-settings: ‘cv08’, ‘cv05’;
There is plenty more in the way of settings and features specified in CSS Fonts Module Level 4. We have just scratched the surface! To keep up with developments, read the specification as it happens here: https://drafts.csswg.org/css-fonts-4/#introduction.
Exercise
Have a look at the CSS from our example page:
</pre> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">:root {</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> --MainFont: 'Helvetica Neue', Helvetica, Arial, sans-serif;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">@font-face {</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-family: 'Inter-V';</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> src: url('fonts/inter.var.woff2') format('woff2-variations');</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-weight: 100 900;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-display: fallback;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-style: oblique 0deg 10deg;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">body {</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> background-color: var(--background);</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> color: var(--foreground);</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> transition: all 0.35s;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-size: 1.2em;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-family: 'sans-serif';</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-family: var(--MainFont);</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-weight: 400;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">@supports (font-variation-settings: 'wdth' 200) {</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> body {</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-family: 'Inter-V';</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-variation-settings: 'wght' 300, 'slnt' -4;</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> font-feature-settings: 'cv08', 'cv05';</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;"> }</p> <p style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; white-space: normal;">}</p> <pre>
How much of that can you now understand? We have a CSS custom property defined for our system font-stack, a font-face loading a variable font, complete with ranges defined for weight and slant. We have sans-serif as the default font-stack, which we then overwrite with the font-stack defined in the custom property for browsers that understand it. Finally, we feature test for variable fonts and define settings for it, also adding in some additional font features we’d like to see.
This brings us to the end of our discussion on web typography. So far in this chapter, we have looked at how CSS has given us new powers of selection and the ability to add custom typography to our designs. Now, we’ll look at ways CSS allows us to work with color.