Skip to main content

Journal

Webfont loading strategies

When it comes to webfonts, if you want to serve an accessible and high performance experience across device types it’s not as straightforward as just specifying your fonts in CSS then hoping for the best.

We likely have goals such as the following:

  • avoid Flash of Invisible Text (FOIT). Flash of Unstyled Text (FOUT) is preferable.
  • provide a good experience for users on slow connections.
  • while favouring FOUT over FOIT, take care to minimise jarring reflows.

Browser support is also a factor. For example font-display: swap seems like a great option however as Chris Ferdinandi pointed out in Why use the vanilla JS fontfaceset.load method instead of CSS font-display: swap it doesn’t have comprehensive mobile support. Since mobile users are regularly on slower connections they are likely to be hit hard by load times incurred due to custom fonts, therefore a solution which doesn’t cater to them is less attractive.

I tend to go for FOUT with a class—an approach that is reliable and good enough for most use cases. The idea is to use JavaScript to detect when a font has loaded successfully, and only then add a fonts-loaded class to the HTML element causing CSS scoped to that class to take effect. To date I’ve handled the detection using Bram Stein’s Font Face Observer to benefit from greater browser support (it handles IE) than I’d get using the native FontFaceSet.load() however I expect to gravitate toward the native API solution soon.

I’ve also experimented with pre-loading fonts in the <head> in combination with font-display: swap on this, my personal website. This was inspired by the font-loading approach Zach Leatherman took with CSS-Tricks. However due to the fonts I’m using right now I’d currently be preloading too heavy a load for slow connections (thus temporarily blocking initial page render) so I’d need to go further and introduce two-stage loading into that mix.

I’ve also found that your choice of font and font host can really influence (constrain) the flexibility and options you have for font features and loading.

  • font-display: swap can only be applied on a self-hosted font or one hosted on Google Fonts (via a special querystring parameter on the font URL). So this CSS-only approach is not available with (for example) fonts hosted on Adobe Fonts or fonts.com.
  • link rel=preload is only available for self-hosted fonts because you need to be able to rely on the URL not changing, and you can’t rely on that for externally hosted fonts.
  • You might want to use the opentype features of a font but are they available in your font hosting/loading solution? Some of the fonts hosted on Google Fonts have nice OpenType features but by default these features are pruned out.
  • Getting access to the source .ttf file is beneficial as it allows you to subset the font, including special features and characters but also cutting out any your website does not require. Google Fonts have an open license which means we don’t need to lean on their hosting but can instead download fonts in .ttf, subset them (I use Glyphhanger) and self-host them.

This is all a work in progress and I’m still working this stuff out.

Animating the underlining of multi-line text

Cassie Evans shows us how to combine background–size, a linear-gradient based background-image and a keyframe animation (all in HTML and CSS) for a lovely progressive underline effect on multi-line text.

Here’s the gist of it:

<h2>This is a multi-line spanning animated underline. This took an annoyingly long time to figure out.</h2>
body {
  padding: 40vh 30vw;
  font-family: cursive;
  text-align: left;
  font-size: 130%;
}

h2 {
  line-height: 1.5;
  display: inline;
  background-image: linear-gradient(
        transparent 50%,
        #e1fffe 50%,
        #b0f8ff 85%,
        transparent 85%,
        transparent 100%
    );
    background-repeat: no-repeat;
    background-size: 0% 100%;
    animation: animatedBackground 2s cubic-bezier(0.645, 0.045, 0.355, 1) 0.5s forwards;
}

@keyframes animatedBackground {
    to {
        background-size: 100% 100%;
    }
}

Thanks, Cassie!

Native lazy-loading for the web

Now that we have the HTML attribute loading we can set loading="lazy" on our website’s media, and the loading of non-critical, below-the-fold media will be deferred until the user scrolls to them.

This can really improve performance so I’ve implemented it on images and iframes (youtube video embeds etc) throughout this site.

This is currently only supported in Chrome, but that still makes it well worth doing.

Fringe Making

Last Tuesday, 20/8/19 I made the train trip east for a day at the Edinburgh Festival Fringe.

There are always a variety of interesting shows to catch in the month-long festival and this year I was particularly looking foward to Darren McGarvey AKA Loki’s Scotland Today. Having read and enjoyed McGarvey’s book Poverty Safari last year I was keen to see and hear him in the flesh.

Another reason for the trip was that during a recent stint working with Bright Signals I developed the FringeMaker web app – a Pokémon Go style game where you win points by “checking into” Fringe gig venues – so I was excited to hit the Edinburgh streets to give it a spin for real.

First port of call was to meet my friends Mick and Laura at George Square for a catch up and pre-gig beer. Having made it through the festival crowds and pouring rain to find them, we took temporary refuge with a pint and some tasty pizza from the nearby stalls, before setting off for our first gig: Tony Slattery’s Slattery Will Get You Nowhere.

Slattery will get you nowhere

In the early nineties I enjoyed watching Tony on Whose Line is it Anyway? and I was moved by a recent Guardian interview which revealed that in the years following the show ending he fell off the rails somewhat due to his bipolar disorder allied to alcohol and drug addictions, and was now looking for an agent and new opportunities.

The format of this show was just Tony and comedy historian Robert Ross sat at a table, with Tony answering a series of unscripted questions. Over the course of an hour he stepped through his career, from winning the Fringe’s inaugural Perrier Award with Cambridge Footlights pals Stephen Fry, Hugh Laurie and Emma Thompson (“yeah but where are they now?”), to pant-splitting (literally) and deleted scenes on Whose Line is it Anyway?, to acting roles in films such as Peter’s Friends. It was filled with funny anecdotes involving the likes of Rik Mayall and Kenneth Branagh, plus a few might-have-been stories such as when he narrowly missed out (to Sylvester McCoy) on the role of Doctor Who.

Overall I really enjoyed this. Despite having problems which have taken their toll, Tony Slattery is still a funny and engaging performer and is also doing his bit to help raise awareness of bipolar disorder. He seems like a good egg.

Scotland Today

Onwards to Darren McGarvey’s show at The Stand’s New Town Theatre, and he unexpectedly begins with a TED Talk style discussion on space and quantum mechanics, setting up the idea that there are two contradictory versions of himself.

There’s the pre- Poverty Safari, lower working class CDE2 Darren; and the new, “poster child for working class politics”, middle-class, ABC1 Darren.

During the show he mostly speaks as the “new Darren”, describing how his situation has improved and priorities changed since no longer having to constantly worry about financial security. He is still angry about the injustices of life in the UK – citing the inadequate response to the Grenfell Tower Disaster as an example – but also realises that he has become a contradiction given his new status.

He moves on to suggest that the ABC1 group are in a privileged position, uniquely placed to get ahead in life while others can’t; and that because they don’t properly understand the circumstances of the CDE2s they are therefore not in a position to be making the decisions that affect them.

He contrasts the comfortable lives of the ABC1s with those of the CDE2s who live in quicksand – constantly being dragged down by financial and other societal problems, with no prospect of getting out and a feeling that by attempting to escape you only make matters worse.

McGarvey finishes by switching to his angry, in-your-face, baseball cap wearing alter-ego from another possible timeline; not blessed with the fortune of middle-class Darren and furious about the injustices of his situation and life in Tory-led Britain.

Again, I really enjoyed this show, and felt that McGarvey was just as powerful in the flesh as on paper, if not more so. There were maybe a few too many narrative devices and gimmicks going on than necessary, but he’s a really interesting voice and continually says things which make me think and challenge myself.

I think his new BBC show, Darren McGarvey's Scotland will definitely be one to watch.

Flexible tag-like functionality for custom keys in Eleventy

I have an open-source, Eleventy-based project where the posts are restaurants, each of which is located in a particular city, and contributors to the repo can add a new restaurant as a simple markdown file.

I just had to solve a conundrum wherein I wanted a custom front matter key, city, to have similar features as tags, namely:

  1. it takes arbitrary values (e.g. Glasgow, or London, or Cañon City, or anything a contributor might choose);
  2. there is a corresponding cityList collection;
  3. there is a page which lists all cities in the cityList collection as links; and
  4. there’s a page for each city which lists all restaurants in that city (much like a “Tagged Glasgow” page).

You could be forgiven for asking: why didn’t I just implement the cities as tags? I could have tagged posts with “glasgow”, or “edinburgh” for example. Well, here was my rationale:

  • for cities, I need the proper, correctly spelled, spaced and punctuated name so I can display it as a page title. A lowercased, squashed together “tag” version wouldn’t cut it;
  • I list “all tags” elsewhere and wouldn’t want the cities amongst them. Although Eleventy allows you to filter given tag values out, in this case that would be a pain to achieve because the city values are not known up front;
  • Lastly it just felt right for ease of future data manipulation that city should be a separate entity.

This task was a bit of a head-scratcher and sent me down a few blind alleys at first. Rightly or wrongly, it took me a while to realise that only all posts for tag values are automatically available as collections in Eleventy. So any other collections you need, you have to DIY. Once I worked that out, I arrived at a strategy of:

implement all the requisite functionalty on tags first, then emulate that functionality for my custom key.

First port of call was the Eleventy Tag Pages tutorial. That showed me how to use the existing “collection for each tag value” to create a page for each tag value – the “All posts tagged with X” convention. (Here’s an example on this site.)

I then referenced the eleventy-base-blog repo which takes things further by creating a page which lists “all tags”. To achieve this you first need to create a custom tagList collection, then you create a page which accesses that new collection using collections.tagList, iterates it and displays each tag as a link. Each tag link points to its corresponding “All posts tagged with X” page we created in the step above.

So now I had everything working for tags. Next step: emulate that for cities.

Here’s what I ended up doing:

Create new file _11ty/getCityList.js

module.exports = function(collection) {
  let citySet = new Set();
  collection.getAll().forEach(function(item) {
    if( "city" in item.data ) {
      let city = item.data.city;
      citySet.add(city);
    }
  });

  return [...citySet];
};

Then add the following to .eleventy.js

// Create a collection of cities
eleventyConfig.addCollection("cityList", require("./_11ty/getCityList"));

// Create "restaurants in city" collections keyed by city name
eleventyConfig.addCollection("cityCollections", function(collection) {
  let resultArrays = {};
  collection.getAll().forEach(function(item) {
    if(item.data["title"] && item.data["city"]) {
      if( !resultArrays[item.data["city"]] ) {
        resultArrays[item.data["city"]] = [];
      }
      resultArrays[item.data["city"]].push(item);
    }
  });
  return resultArrays;
});

Next, create new file cities-list.njk:

---
permalink: /cities/
layout: layouts/home.njk
---
<h1>All Cities</h1>

<ul>
{%- for city in collections.cityList -%}
  {% set cityUrl -%}/cities/{{ city }}/{% endset %}
  <li><a href="{{ cityUrl | url }}">{{ city }}</a></li>
{%- endfor -%}
</ul>

Finally, create new file posts-in-city.njk:

---
renderData:
  title: Restaurants in “{{ city }}”
pagination:
  data: collections.cityList
  size: 1
  alias: city
permalink: /cities/{{ city | slug }}/
---
<h1>Restaurants in {{ city }}</h1>

{% set postslist = collections.cityCollections[ city ] %}
{% include &#39;postslist.njk&#39; %}

And that’s a wrap! Eleventy will do the rest when it next runs, creating for each city a page which lists all restaurants in that city.

Footnote: I should acknowledge this 11ty Github issue in which Ed Horsford was trying to do something similar (create a separate tags network) leading to Zach Leatherman pitching in with how he created noteTags for his website’s Notes section. That led me to Zach’s website’s repo on Github, specifically .eleventy.js and tag-pages.njk, without which I wouldn’t have found my way.

Get Waves

I’ve been admiring the wave effect at the foot of banners on Netlify’s website and had noted that they were achieved using SVG. So this tool which helps you “make waves” is pretty timely!

In second year a nice school pal introduced me to The Cure when I was on an otherwise strict diet of rave tapes. Mixed Up with its dubby extended mixes sealed the deal. Shamefully haven’t yet seen them live so I’m at fever pitch for tomorrow’s gig at Bellahouston Park. Hopefully see some of you there!

---

Must have missed this track (from the LP The Sorrow of Derdriu) on previous listens. A Bladerunner-esque beauty!

From dynamic to static

“I’ll just make a few small tweaks to my website…” said I. Cut to three sleep-deprived days later and I’ve rebuilt it, SSG/JAMstack-stylee with Eleventy and Netlify and entirely re-coded the front-end. Silly, but so far so good, and it’s greasy fast!

So yes, I’ve just updated my website from being a dynamic, LAMP-stack affair which used Perch CMS and was hosted on Linode to being statically-generated using Eleventy and hosted on Netlify.

It mostly went smoothly. And the environmental and continuous deployment boilerplate that Netlify provide are fantastic, and will be a real time-saver over my current “set up and maintain a Linode server” approach.

In terms of challenges and troubleshooting, I did have to find a solution to the issue of FOUT on repeat visits. It seems this was happening as a result of Netlify’s interesting approach to asset caching which works well for most requirements but wasn’t so great for self-hosted webfonts. My solution was to add specific headers for .woff and .woff2 files in my application’s Netlify config file.