To provide a consistent experience to web users, developers have two choices with regards their font selection. Choose a Web Safe font such as Arial or Times New Roman that is likely to be installed on the user’s machine or provide a font directly to the user. Given the limited font selection for the former and associated perceived burden of the latter, many developers opted for using a service such as Google Fonts to provide a fast repository of usable web fonts.
Since the adoption of the General Data Protection Regulation (GDPR) [1] and California Consumer Privacy Act (CCPA) [2], it has been demonstrated [3] that Google Fonts is non-compliant. Developers are required to seek consent before importing fonts from this provider and provide a fallback if the user declines, which can be difficult to implement.
This post highlights three alternative options to using Google Fonts that are GDPR and CCPA compliant:
- Bunny Fonts
- Cloudflare Fonts
- Self-hosting
Given the importance of privacy and the increasing role of web technologies in the field of Data Science, the post is applicable for general web enthusiasts but also computional based writers using tools such as Jupyter Book, Quarto, or Bookdown.
The post is the basis for a podcast on this topic called: Privacy Compliant Web Fonts.
Introduction to Fonts on Websites
The Hyper Text Markup Language (HTML) specification originally including a <font>
tag but was deprecated in favour of using Cascading Style Sheets (CSS). Although there are authoritative definitions for HTML [4] and CSS [5] a more user friendly guide is the Mozilla Developer Network. Typically, the developer specifies a font and associated attributes using the following CSS. Note we are applying this to anything within the <html>
tag i.e. the entire page.
styles.css
html {font-family: 'Arial';
}
To illustrate the concepts we’ll use the following HTML structure that links to an empty style sheet called style.css
.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Hello, world!</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<header>
<h1>Example Web Page</h1>
</header>
<main>
<section>
<h2>Introduction</h2>
<p>Example paragraph.</p>
</section>
</main>
<footer>
<p>© 2024 Example Company</p>
</footer>
</body>
</html>
The fonts in the figure above are the default provided by the browser and vary by browser, browser version and operating system. If we add the font-family
definition to the styles.css
file it provides the following output:
We can inspect the structure of any web page using the Developer Tools, activated by pressing F12, Ctrl-Shift-I, Cmd-Shift-I, through the menu system or by right clicking on an element and selecting Inspect. The example below is for Mozilla Firefox:
The figure below shows how a user could determine the assigned font for any HTML element, in this instance the <h2>
tag:
The browser was able to accurately represent the designers / developers intent as the font was available on the user’s machine. But what if we want to a more exotic or brand specific font for our headings? For example, the Holtwood One SC as illustrated on Google Fonts:
The CSS file has been updated to target the <h1>
tag with the new font:
styles.css
html {font-family: "Arial";
}
h1 {font-family: "Holtwood One SC";
}
The updated web page however doesn’t look as expected:
It appears the browser has used its default font for the <h1>
tag. This can be confirmed using the Developer Tools, which when the fonts tab on the right hand side shows the actual fonts in use:
The tool confirms that Times New Roman is the actual font in use. This demonstrates an important principle that the browsers must have access to the font to render it correctly. To mitigate the absence of fonts, one of two fallback font groups can be specified as either serif
or sans-serif
. In this instance we’ll use serif
:
styles.css
html {font-family: "Arial", sans-serif;
}
h1 {font-family: "Holtwood One SC", serif;
}
Whilst this allows a worst case reasonable substitute font to be selected by the browser, it doesn’t reflect the designer’s intent. An alternative approach is to provide a selection of fonts which are likely to be available on a users’ machine. The challenge is finding a selection of fonts that covers a wide range of devices and operating systems. There is no definitive list, even the most widely recommend font “Arial” isn’t installed by default on some Linux distributions. In practice this means the designer must trade between commonality and complexity in specifying multiple fonts.
The classic “Web Safe” fonts [6], [7] are (depending on the source):
- Arial
- Courier New
- Georgia
- Times New Roman
- Trebuchet MS
- Verdana
- Tahoma
- Garamond
- Brush Script MT
These fonts may seem familiar as the are largely driven by the Microsoft Windows operating system. They also don’t reflect the dominance of mobile devices which operate on flavours of iOS and Android. There are tools that provide greater granularity [8] in identifying fonts that are available for both Windows and Mac OS X. however it’s common practice to reuse existing lists from popular CSS Frameworks such as Bootstrap:
_variables.scss
$font-family-sans-serif:
system-ui,
,
-apple-system"segoe ui",
,
roboto"helvetica neue",
"noto sans",
"liberation sans",
,
arialsans-serif,
"apple color emoji",
"segoe ui emoji",
"segoe ui symbol",
"noto color emoji" !default;
Bootstrap uses a CSS extension called SASS, which is why the formatting doesn’t look like standard CSS but nonethless we can see it shows a modern font stack that is likely to be available on a user’s machine. To guarantee the font is available, there are three options:
- Link to a font asset file from an external provider
- Import a web font from an external provider using CSS
- Host the font and make it available to the user
Even in all three of these scenarios there is in practice no guarantee that the font will be available to the user. Many companies may have security or IT policies in place that prevent downloading and using external fonts but these options remain the most practical methods to convey the designer’s intent.
Web Fonts
The CSS @font-face
rule allows for the inclusion of fonts in a web page and with the exception of Microsoft Edge1 it has been supported by the major browsers since 20102.
1 Microsoft Edge itself was released in 2015 and this feature was supported from launch. It’s predecessor Internet Explorer supported the featured from 2010.
2 Can I Use… Browser Compatibility Check to determine support for the @font-face
rule.
The first method is a link to an external stylesheet as illustrated using Google Fonts:
index.html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Holtwood+One+SC&display=swap" rel="stylesheet">
styles.css
h1 {font-family: 'Holtwood One SC', serif;
}
The <link>
tags go in the <head>
section (below) and the CSS (above) is inserted into the style.css
; the updated HTML code is shown below:
index.html
<head>
<meta charset="UTF-8" />
<title>Hello, world!</title>
<!-- Method 1: External Stylesheet -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Holtwood+One+SC&display=swap" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
The updated web page now has the correct font:
The second method is to use the CSS import method using the @import
rule:
index.html
<style>
@import url('https://fonts.googleapis.com/css2?family=Holtwood+One+SC&display=swap');
</style>
The @import
rule can be placed within a set of <style>
tags in the <head>
section or directly in a CSS file prior to it’s use. In either case, the designer is no longer dependent on the user having the font installed on their machine.
Privacy Compliant Web Fonts
As stated at the beginning of the post, Google Fonts is a popular external provider of often free-to-use web fonts. Since the adoption of GPDR and much later the CCPA, the use of Google Fonts is inconsistent with these regulations unless explicit permission is sought first. To mitigate these concerns developers can either use a provider that anonymizes the data collected when the end user accesses the font files or self-host the font files.
Bunny Fonts
Bunny Fonts advertises itself as fully GPDR compliant:
Bunny Fonts is an open-source, privacy-first web font platform designed to put privacy back into the internet.
With a zero-tracking and no-logging policy, Bunny Fonts helps you stay fully GDPR compliant and puts your user’s personal data into their own hands. Additionally, you can enjoy lightning-fast load times thanks to bunny.net’s global CDN network to help improve SEO and deliver a better user experience.
Fonts can be browsed directly at Bunny Fonts using a similar interface and even the code is the same syntax as Google Fonts but where the URL https://fonts.bunny.net/css
replaces https://fonts.googleapis.com/css
as shown below:
index.html
<head>
<meta charset="UTF-8" />
<title>Hello, world!</title>
<!-- Method 1: External Stylesheet -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=holtwood-one-sc:400" rel="stylesheet" />
<!-- Method 2: CSS Import -->
<style>
@import url('https://fonts.bunny.net/css?family=holtwood-one-sc:400');
</style>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
Cloudflare Fonts
Cloudflare Fonts automatically (when activated) re-writes references to Google Fonts to serve the same fonts from within Cloudflare improving performance and eliminating some privacy concerns. It requires the use of Cloudflare services and manual activation. It’s therefore not as flexible or useful as Bunny Fonts, which is available to all developers without creating an account or serving traffic through a particular Content Deilvery Network (CDN).
Self-Hosting
Whilst both Bunny and Cloudflare fonts offer an equivalent privacy compliant service, the user must trust that these organisations are indeed compliant - there is no external validation. To migigate this the fonts can be self-hosted and delivered typically as the Web Open Font Format (WOFF) [9].
There are a number of tools that perform the conversion from Google (or Bunny) fonts into a WOFF
package such as Google Web Fonts Helper. The service defines the required CSS and provides the converted font files in a zip archive.
The designer can then host the fonts on their own server and link to them in the same way as the other methods:
styles.css
/* holtwood-one-sc-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Holtwood One SC';
font-style: normal;
font-weight: 400;
1src: url('../fonts/holtwood-one-sc-v20-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
- 1
- Note the relative path of the location for the fonts.
Once the font has been imported via @font-face
it can be used in the same way as other methods. Here is an updated example styles.css
incorporating the self-hosted font:
styles.css
/* holtwood-one-sc-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Holtwood One SC';
font-style: normal;
font-weight: 400;
src: url('../fonts/holtwood-one-sc-v20-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
html {font-family: "Arial";
}
h1 {font-family: "Holtwood One SC", serif;
}
The example shows how a font can be converted, downloaded and served by the developer to the user using CSS, bypassing the privacy concerns associated with external font providers.
Modify Quarto Fonts
To illustrate the principles highlighted in this post, here is an example related to Quarto. There are several locations where customising fonts for the HTML format are discussed in the Quarto Documentation:
The first link provides a direct property called mainfont
however requires any font named to be installed on the user’s machine. A better approach is the combination of the second and third links that allow for the use of SASS variables to define the font stack in a fonts.scss
file. The following example uses Roboto Slab from Bunny Fonts:
fonts.scss
/* Quarto SASS Variables from: https://quarto.org/docs/output-formats/html-themes.html#sass-variables
Bootstrap SASS Definitions from: https://github.com/twbs/bootstrap/blob/main/scss/_variables.scss */
/*-- scss:defaults --*/
// Import Fonts from Bunny Fonts
@import url(https://fonts.bunny.net/css?family=roboto-slab:400);
// Copy of Bootstrap Font Stack
$font-family-sans-serif:
"Roboto",
"Noto Sans",
system-ui,
,
-apple-system"Segoe UI",
,
Roboto"Helvetica Neue",
"Noto Sans",
"Liberation Sans",
,
Arialsans-serif,
"Apple Color Emoji",
"Segoe UI Emoji",
"Segoe UI Symbol",
"Noto Color Emoji" !default;
$font-family-monospace: "JetBrains Mono", SFMono-Regular, Menlo, Monaco,
, "Liberation Mono", "Courier New", monospace !default;
Consolas
// H1 fonts and then contents for $font-family-sans-serif
h1 {font-family: "Roboto Slab", $font-family-sans-serif;
}
The <h1>
tag pre-appends the new font but as we can’t guarantee the user can download fonts at all, it’s useful to specify the default font-stack as a fallback.
The custom SCSS file can be incorporated into the _quarto.yaml
as follows:
format:
html:
theme:
- superhero
- fonts.scss
This loads the custom fonts.scss
after the baseline theme (in this case superhero
).
Conclusion
This guide showed that unless the user has the required fonts installed, the designer’s intent will not be met as the browser will substitute with an alternative font if not available. To mitigate this, a popular choice is to use a web font (a feature available to most browsers since 2010) from an external font provider such as Google Fonts. However, it has been demonstrated that Google Fonts is not GPDR compliant and therefore the user has two options. Trust an alternative provider such as Bunny Fonts, who promises not to collect any data or self-host. Both methods have been discussed and appropriate examples provided. Finally, how to incorporate custom fonts into a Quarto site has been demonstrated.
Attribution
Profile Image based on Martin Herfurt from Pixabay.
Assets by Pete Linforth from Pixabay
References
Citation
@online{2024,
author = {, miah0x41},
title = {GPDR {Web} {Fonts}},
date = {2024-04-28},
url = {https://blog.curiodata.pro/posts/03-gpdr-web-fonts},
langid = {en}
}