How my butt helped fix font problems on the web

We recently decided to update the typography on Lemi, our platform for inspired travel recommendations. When our users create a list of places, and want to share them with friends, we automatically generate a beautiful web sharing page like this with a cover photo, map, and list of places, photos and writeups.

Previously we were using everyone’s favorite font Helvetica, but we wanted to show off our users’ creations with a font everyone could get behind.

“Helvetica is good for typographers who do not know what to say.”

― Thomas Bohm

The Linux distribution Red Hat have developed two fonts Red Hat Display and Red Hat Text inspired by the legible typography of classic transportation fonts like Interstate and Overpass, which were ideal for our purposes.

We recently started moving our homepage and sharing pages over to use Red Hat. However, with pages being dynamically generated and multiple stylesheets, it was easy to have some small errors on some pages, such as text being the wrong weight, size or font family.

In Chrome, you can right-click on any element and quickly inspect its properties. In the “Computed” tab of the Elements section, here we can quickly verify that Red Hat Text Medium is applied, and check the font size and weight.

However doing this for every element on the page is slow and time-consuming, so I wondered if there was a way we could easily check the font properties of all the elements on a page at once.

The idea would be to replace each text node on a page with the name of the font style that was applied while leaving the layout unchanged. Before I got too far in attempting to code this, I realized that I had seen this problem solved before years ago, specifically in a Chrome extension called Cloud-to-Butt.

Cloud-to-Butt makes fun of the tech industry’s obsession with talking about The Cloud by replacing all instances of “the cloud” on a webpage with “my butt”, to often hilarious effect:

In order to modify the text without affecting the layout of the page, extensions like these walk through the DOM tree, recursively looking for nodes with a text type. When they find one, they do a search-and-replace of the text inside.

function walk(node) 
{
   //see https://github.com/panicsteve/cloud-to-butt/blob/master/Source/content_script.js
}


function handleText(textNode) 
{
	var v = textNode.nodeValue;

	v = v.replace(/\bThe Cloud\b/g, "My Butt");
	v = v.replace(/\bThe cloud\b/g, "My butt");
	v = v.replace(/\bthe Cloud\b/g, "my Butt");
	v = v.replace(/\bthe cloud\b/g, "my butt");
	
	textNode.nodeValue = v;
}

walk(document.body)

For my version of the code I would remove all the butt stuff, and instead replace the node value with the computed style of the text node’s parent.

The main “trick” is the use of window.getComputedStyle, which given a DOM node returns the CSS style object computed for that node, similar to the panel in Chrome. We need to run this on the parent of the text node, as text nodes themselves don’t have a style. We then compute a string like “RHD 40 Medium” (where RHD is an abbreviation for Red Hat Display)

function handleText(textNode) {
  //get the text in the text node
  var v = textNode.nodeValue;
  
  // get the computed style of the text node's parent, for example <p>Some text</p> will get the computed style of the parent node
  var cs = window.getComputedStyle(textNode.parentNode)

  //skip replacing inline style and script nodes
  if (cs && textNode.parentNode.nodeName != "STYLE" && textNode.parentNode.nodeName != "SCRIPT") {

    //get font family, size and weight
    let font = cs.fontFamily || ""
    let size = cs.fontSize
    let weight = cs.fontWeight
    //use friendly weight names
    let weights = {
      100: "Thin",
      200: "Extra Light",
      300: "Light",
      400: "Regular",
      500: "Medium",
      600: "Semibold",
      700: "Bold",
      800: "Extra Bold",
      900: "Black"
    }


    //trim off fallback fonts
    font = font.replace("sans-serif", "").replace(/[,"]/g, "").trim()

    //abbreviate RHT and RHD
    font = font.replace("Red Hat Text", "RHT").replace("Red Hat Display", "RHD")

    //replace!
    textNode.nodeValue = font + " " + size + " " + weights[weight]
  }
}

Running this on a page like this:

Immediately outputs this

At a glance you can scan over the page and see that all the header links are the correct size and font – but what’s this? A cheeky Helvetica has made its way onto the page!

With the power of a little Javascript and my butt, we were able to rapidly make fixes and apply the correct font across all our pages!

Check out the gist and feel free to adapt to your purposes, and visit Lemi to make your own ass-tounding list.