Web Development
Why should you preload fonts?

Why should you preload fonts?

There are two ways you can arrive at wanting to preload fonts on a webpage.

The first is your running a lighthouse test for page speed, and scoring badly for cumulative layout shift (CLS). This is the measure of how long elements on the page are shifting position as the page is loaded. This can be impacted by a font load causing elements on a page due to custom fonts having a different size to the default browser font initially used in rendering.

The second is that you can visually see the font switching from default to custom and want to eliminate this.

Now the best way to eliminate both of these issues is to just use browser fonts from the start and that way no font needs to be downloaded in the first place, but the chances are that's not an acceptable solution for your stakeholders.

What is the normal browser behavior?

To use a custom font you first need to define that font as a @font-face in CSS. It will look something like this.

1@font-face {
2 font-family: "Bitstream Vera Serif Bold";
3 src: url("https://mdn.github.io/css-examples/web-fonts/VeraSeBd.ttf");
4}
5
6body {
7 font-family: "Bitstream Vera Serif Bold", serif;
8}

You will likely define this in a stylesheet file referenced from your HTML page. This means that the browser will first download the HTML page containing text to display, but won't have any way of knowing about the font until the CSS file has been downloaded.

What's worse, the browser is also going to try lazy loading all the font's in. Meaning just because it see's the font-face definition in the stylesheet, it's not going to do anything with it until it knows it's going to be applied to a style on the page, and only then will it start downloading the font.

How to preload a font

To avoid these issues you can tell the browser to preload the font by adding a Link element to the head of the document.

1<head>
2 <!-- ... -->
3 <link rel="preload" href="/assets/Pacifico-Bold.woff2" as="font" type="font/woff2" crossOrigin='anonymous'>
4</head>

This link element tell the browser that the font is going to be used and it should download it as early as possible. Lets break down the attributes:

link - tells the browser to preload the font.

href - the url of the file to download.

as and type- what type of file this is. In this case its a font with a mime type of font/woff2.

crossOrigin - an interesting quirk with browsers, unless you set this the file wont get downloaded even if your hosting the font yourself.

Best Practices with Fonts

Here are some more best practices to follow with fonts.

Minimize the number of custom fonts

The best way to avoid issues with loading font's is to use as few custom fonts as possible. Essentially the more you add the more that will need to be downloaded.

Although fonts can be preloaded via preloading, you are only ever optimizing the critical path to show the webpage, it won't do anything to reduce the total data needing to be downloaded. A browser is also limited in the number of requests it will make at a time, meaning the more files there are, the more that will ultimately get queued.

Only Preload the main font

To ensure browser support your font-face definition might actually contain multiple font files of different types.

1@font-face {
2 font-family: 'MyWebFont';
3 src: url('myfont.woff2') format('woff2'),
4 url('myfont.woff') format('woff');
5}

When the browser reads these definitions they will pick the first in the list with a format that they support and ignore the rest. However if you add a Link tag to preload each of them, the browser will have no way of knowing it is an order of preference and download them all. Therefore you should only preload the first in the list. This will likely be a woff2 that's supported by basically all modern browsers.

Security Headers in Next.JS

Security Headers in Next.JS

To ensure your site is protecting its users. several security headers can be set to help prevent certain attacks against websites.

For Next.JS these are set in the next.config.js file. Typically I use the following config.

1/** @type {import('next').NextConfig} */
2const nextConfig = {
3 async headers() {
4 return [
5 {
6 source: '/:path*',
7 headers: [
8 {
9 key: 'X-Frame-Options',
10 value: 'SAMEORIGIN',
11 },
12 {
13 key: 'Content-Security-Policy',
14 value: "frame-ancestors 'none'",
15 },
16 {
17 key: 'Referrer-Policy',
18 value: 'same-origin',
19 },
20 {
21 key: 'Strict-Transport-Security',
22 value: 'max-age=15768000',
23 },
24 {
25 key: 'X-Content-Type-Options',
26 value: 'nosniff',
27 },
28 {
29 key: 'X-XSS-Protection',
30 value: '1; mode=block',
31 },
32 ],
33 },
34 ];
35 },
36};
37
38module.exports = nextConfig;
39

Content-Security-Policy

Setting frame-ancestors: none is similar to X-Frame-Options and will prevent a site loading in an ancestor frame, iframe. object or embed.

X-Frame-Options

Indicates whether a browser should be allowed to render a page in a frame, iframe, embed or object tag. By setting to SAMEORIGIN this ensures the site is only rendered in this way on itself and not on other sites.

Click-jacking attacks commonly use display other sites within themselves to fool a user as to what site they are on.

Referrer-Policy

Referrer Policy sets how much information is sent with the referrer header. By setting to same-orign, the referrer header is only sent on same origin requests.

Strict-Transport-Security

This header instructs the browser to only access the site over https. By setting the age it instructs the browser to remember this setting for the number of seconds given.

X-Content-Type-Options

Setting to nosniff will block a request if the destination is of type style and the MIME type is not text/css, or of type script and the MIME type is not a JavaScript MIME type.

X-XSS-Protection

This is a non-standard header and isn't supported in any current browsers but has history support with Chrome and Edge.

The header instructs the browser how to handle any cross-site scripting attacks it detects on the page. Setting to 1; mode-block will prevent the page from rendering if an attack is detected.

Knowing what type your object is in C# 8

Knowing what type your object is in C# 8

If your familiar with object oriented programming then you'll know one of the advantages is classes can be designed to inherit from base classes to avoid duplication in your code. In fact in C# all classes ultimately inherit from the base class object. So if you had a list of objects, it would be valid that any object could be added to the list.

Lets look at a scenario of a library where people can borrow Books, DVDs and Games. All will have a Title and Barcode, but each type will also have some more specific properties.

1public class BaseClass
2{
3 public string Name { get; set; }
4 public string Barcode { get; set; }
5}
6
7public class Book : BaseClass
8{
9 public int Pages { get; set; }
10}
11
12public class DVD : BaseClass
13{
14 public int RunningTime { get; set; }
15}
16
17public enum GameConsole
18{
19 Playstation,
20 Xbox
21}
22
23public class Game : BaseClass
24{
25 public GameConsole Format { get; set; }
26}

Those are some classes. Some example data for a members borrowings could be like this.

1List<BaseClass> membersLoans = new List<BaseClass>();
2membersLoans.Add(new Book() { Name = "A Christmas Carol", Barcode = "123", Pages = 210 });
3membersLoans.Add(new DVD() { Name = "Wonka", Barcode = "124", RunningTime = 180 });
4membersLoans.Add(new Game() { Name = "Alan Wake 2", Barcode = "125", Format = GameConsole.Xbox });

Now we have a list of what a member has borrowed we can output the list using a foreach loop.

1foreach (var item in membersLoans)
2{
3 Console.WriteLine(item.Name);
4}
5
6/*
7Ouput
8------------------------
9A Christmas Carol
10Wonka
11Alan Wake 2
12 */

That's a list of the titles, but what if we want to add more info such as the type and some of the details from that type. These are outside the properties of BaseClass so we will need some way of knowing what type of object item is and then cast to that object.

Type checking in C# using 'is'

The is keyword can be used to determine if an instance of an object matches a pattern, such as an object type or null. We can use some if else statements check what are type is.

1foreach (var item in membersLoans)
2{
3 if (item is Book)
4 {
5 Console.WriteLine($"{item.Name}, {((Book)item).Pages} pages");
6 }
7 else if (item is DVD)
8 {
9 Console.WriteLine($"{item.Name}, {((DVD)item).RunningTime}mins");
10 }
11 else if (item is Game)
12 {
13 Console.WriteLine($"{item.Name}, {((Game)item).Format}");
14 }
15}
16
17/*
18Ouput
19------------------------
20A Christmas Carol, 210 pages
21Wonka, 180mins
22Alan Wake 2, Xbox
23 */

Type checking using switch

With C# 7 switch expressions become more lightweight and now also support patterns, so rather than all those if else statements, we can combine them all into one simple switch.

Unlike a traditional switch statement the switch returns a result, the case keyword is removed, colons are replaced with =>, and the default keyword is replaced with an underscore.

1foreach (var item in membersLoans)
2{
3 var result = item switch
4 {
5 Book => $"{item.Name}, {((Book)item).Pages} pages",
6 DVD => $"{item.Name}, {((DVD)item).RunningTime}mins",
7 Game => $"{item.Name}, {((Game)item).Format}",
8 _ => item.Name,
9 };
10 Console.WriteLine(result);
11}
12
13/*
14Ouput
15------------------------
16A Christmas Carol, 210 pages
17Wonka, 180mins
18Alan Wake 2, Xbox
19 */

That's all there is to it. We can now mix our objects together and work out what's what as simply as checking the value of a property.

Storybook + NextJs with TypeScript Paths set

Storybook + NextJs with TypeScript Paths set

Previously I have written about making your code neater by using TypeScript paths. Since then I have found that the NextJs create app Wizzard now asks you about setting this, so that from the get-go you will now likely start with it set in an application and have neater code for the better.

However, if you then try using Storybook then you're likely to see an error Module not found: Error: Can't resolve '@/components...' on any component that has an import using one of the paths.

Storybook error relating to paths

Quite simply, Storybook does not pick up the setting in your tsconfig.json file and it has no idea where to import the module from.

To get around this issue we need to also tell Storybook about the paths we've set in .storybook\main.ts. We do this by adding a resolve alias to the config returned by webpackFinal. The code example here sets an alias that will match the default path set by NextJs in its create app wizzard.

1import type { StorybookConfig } from "@storybook/nextjs";
2import path from "path";
3
4const config: StorybookConfig = {
5 // Other config removed for clarity
6 webpackFinal: async (config, { configType }) => {
7 if (!config.resolve) {
8 return config;
9 }
10
11 config.resolve.alias = {
12 ...config.resolve.alias,
13 "@": path.resolve(__dirname, "../src"),
14 };
15
16 return config;
17 },
18};
19export default config;
20

Of course if you have other paths set then you can add them here as well. When you next run storybook the error should be gone and your components now show in Storybooks UI.