Add Typekit fonts to your website built with Jekyll without making an additional request and slowing down performance.
Typekit is a powerful way to add custom fonts to your project. There are three methods Typekit offers for adding its fonts to your site and making them available to use within your CSS files. And there is a(t least one/) problem with each method. First, let's look at the options:
The first way is to link to an external stylesheet:
<link rel="stylesheet" href="https://use.typekit.net/[tk_id].css" />
Next, you can use the @import
CSS at-rule directly within a CSS file:
@import url("https://use.typekit.net/[tk_id].css");
And last you can use JavaScript to load the code asynchronously:
(function(d) {
var config = {
kitId: '[tk_id]',
scriptTimeout: 3000,
async: true
},
h=d.documentElement,t=setTimeout(function(){h.className=h.className.replace(/\bwf-loading\b/g,"")+" wf-inactive";},config.scriptTimeout),tk=d.createElement("script"),f=false,s=d.getElementsByTagName("script")[0],a;h.className+=" wf-loading";tk.src='https://use.typekit.net/'+config.kitId+'.js';tk.async=true;tk.onload=tk.onreadystatechange=function(){a=this.readyState;if(f||a&&a!="complete"&&a!="loaded")return;f=true;clearTimeout(t);try{Typekit.load(config)}catch(e){}};s.parentNode.insertBefore(tk,s)
})(document);
The problem with each of these is that they make an additional request for the Typekit assets. (There's an additional issue with the first and the third approaches in that you have some extra work to do to avoid FOUT).
How do we get around making that additional request?
To avoid the request for the Typekit stylesheet, we could look at the contents of the file and copy them directly into our CSS stack. For example, one of my kit's main CSS file looks like this:
https://use.typekit.net/[tk_id].css
/* Lots of comments up here ... */
@import url("https://p.typekit.net/p.css?s=1&k=[tk_id]&ht=tk&f=32226.32227.32230.32231.39710.39712&a=2470098&app=typekit&e=css");
@font-face {
font-family: "din-2014";
src: url("https://use.typekit.net/af/4b34d2/00000000000000003b9b0acf/27/l?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=i4&v=3")
format("woff2"), url("https://use.typekit.net/af/4b34d2/00000000000000003b9b0acf/27/d?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=i4&v=3")
format("woff"),
url("https://use.typekit.net/af/4b34d2/00000000000000003b9b0acf/27/a?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=i4&v=3")
format("opentype");
font-style: italic;
font-weight: 400;
}
/* More font faces down here ... */
.tk-din-2014 {
font-family: "din-2014", sans-serif;
}
.tk-unit {
font-family: "unit", sans-serif;
}
You could just copy the contents of this right into our project, and in many cases you'd probably be fine.
But notice the URL used for the actual fonts. They are dynamic and -- being that they are controlled by Typekit -- could change at any point. One day your fonts could be working fine, the next they could be broken and you'll have to remember to go find your Typekit file again and replace it with the new contents.
If you're willing to take on that risk, you can stop here.
Alternatively, you could write a Jekyll plugin to go fetch the Typekit CSS file's contents and write them into a file within your project, rather them referencing them externally. The benefit to this approach is that every time you build your project the file is updated with the content Typekit is serving. So if Typekit changes the URLs to their font files all you have to do is rebuild your project and voila! it's fixed!
The first thing I'd do is abstract the variables to a site config object so you don't have to dig into the plugin if it changes:
_config.yml
typekit:
src: https://use.typekit.net/[tk_id].css
dest: _assets/stylesheets/_fonts.scss
And the plugin could look something like this:
_plugins/hooks/typekit_hook.yml
require 'open-uri'
Jekyll::Hooks.register(:site, :after_init) do |site|
# Require typekit config options.
if site.config.dig('typekit', 'src').nil? || site.config.dig('typekit', 'dest').nil?
raise "Missing required Typekit config."
end
# Download CSS from TypeKit.
typekit_url = site.config.dig('typekit', 'src')
css_content = open(typekit_url) { |f| f.read }
# If CSS is different from what we currently have, write to file.
css_file = site.config.dig('typekit', 'dest')
unless css_content == File.read(css_file)
File.open(css_file, 'w+') { |f| f.write(css_content) }
end
end
There's nothing else to do. Jekyll loads plugins automatically from the _plugins
directory, so the next time you build your project, this will take effect.
Notice in this example that I'm writing the file to _assets/stylesheets/_fonts.scss
. This is a Sass file that I then consume in the manifest CSS file. I encourage you to use an approach like this otherwise you'll still end up with another request.
But we're not going to cover configuring your asset pipeline here. If you don't have an asset pipeline in your Jekyll project, check out Jekyll Assets.