URLs, Query Params, and Goofy Google Fonts
URLs are amazing. Not only are they the backbone of the web, they're a great metaphor for a nearly-universal model of making things accessible and interrelated. My favorite apps around today are using URLs in amazing ways. Look at how Figma exposes the ability to link to specific areas of your project and share them, or how much convenience magic links add to authentication for apps like Slack.
Here's an example of a share link from Figma that takes you directly to a specific artboard in my project:
https://www.figma.com/file/JGHehUkuIbxS4eUEwZZ3NR7d/Megan-Rodgers?node-id=31%3A176
Let's break it down. Once we get past the domain we see file/
. In Figma there are a few main routes including files/
, community/
, and so on, and file/
is where all your projects live.
Next there is a monstrous string of letters and numbers (JGHehUku...NR7d/
). This is an ID to your project, most likely generated by applying a hash function to your project's name and other variables. This could actually have a lot of information baked into it and we wouldn't know, because that's one of the main points of using hash functions: encrypting data that you want to share without being spied on. It's the same concept that powers Slack's magic links. What they do is take your username and password (and probably other data) and use it as the seed for an encrypting hash function. Slack can let you share that link with whoever you like without worrying you'll get hacked, because their service is the only one with the key to unencrypt it.
Back in our Figma URL we see a nice human-readable string, the name of the project (Megan-Rodgers
). This seems to just be for users to understand what URL they've copy-and-pasted when they look back at it, because the hash string preceding differs among projects on the same user account. Nice of Figma to make those readable! Invision, for example, choses to make their share links nice and short, but have the trade off that you can easily forget what that link went to if you don't label it when pasting it into an email.
Finally the powerful part is the query parameter ?node-id=31%3A176
. The "?" signals that we're past the normal URL, and into a set of key-value pairs. In this case the key "node-id" has a value of "31%3A176". If there were more parameters they would be separated by an ampersand (&), and each would take the form of "key=value".
Figma is adding a bit of nicety to its share links so that the when you share a link to your work with someone they arrive on the same artboard you were looking at, not some random starting point or the first artboard created, which could be really disorientating in large projects. This is not unlike linkable headings on sites like this one, which lead whoever you share them with to roughly the same area of the post you were reading. But unlike the #identifier
link system which is built into browsers, with query parameters you have to write all the logic yourself.
They had to do two things to make this low-key feature available:
- Write logic to generate a URL with the node id on Share.
- Write logic to listen for certain query parameters like
node-id
on page load and respond accordingly.
Hey, that's an API!
So if we wanted to make a little in-page api, all we'd need is a script that listens for certain query parameters and responds accordingly if it comes across one it knows the action for.
Google Fonts Changing Room
Using the concepts outlined above, I added a short script on my base page template for my 11ty site (on the previous version of this site). It listens for a font
query parameter, and if it finds one it inserts a font <link>
tag into the page with a generated URL to Google Fonts with the corresponding value, then sets the page's font-family style attribute to that font.
Try it out now. Here's this page with Bellota, with Fira Sans, and with Indie Flower.
Here's the entire script to make this possible:
window.addEventListener('load', () => {
const searchParams = new URLSearchParams(window.location.search)
if (!searchParams || searchParams === null) return
const hasFontParam = searchParams.has('font')
if (!hasFontParam || hasFontParam === null) return
const fontVal = searchParams.get('font')
const fontLink = document.createElement('link')
fontLink.href = `https://fonts.googleapis.com/css?family=${ fontVal }&display=swap`
fontLink.rel = "stylesheet"
document.head.appendChild(fontLink)
document.body.style.setProperty('--font-family', fontVal.replace('+', ' '))
})
The URLSearchParams
interface is your tool to parse those params. The window.location.search
property is the portion of your page's URL starting with the "?" that begins the query parameters. If you pass that into the URLSearchParams
you are returned an Iterator that you can work with much like an Object.
The .has(someName)
method returns true
or false
whether a parameter with the name "someName" was found. If we do find the "font" parameter on our URL, we get its value by calling the .get(someName)
method.
Now that we have the font name, we'll create a link tag and set its href
(link location) property to a URL that follows Google Fonts' URL pattern, but with our font value inserted. We tell the browser this is a stylesheet by setting the rel
attribute to "stylesheet", then add the link element to the head of our document.
Finally, we set the font family of the page to the new font we've made available. I've used a CSS Variable here (--font-family
instead of font-family
) to let me keep the direct assignment of the font-family on the body as a fallback. That way if someone enters in a string that isn't a Google Font the page still looks nice, and nothing changes. The URLs of Google Fonts have pluses instead of spaces so I expect the user to follow the same pattern, and I call the .replace(string1, string2)
method to get spaces instead when setting the CSS value.
Conclusions
APIs aren't just for servers! There are tons of interfaces within the frontend of the web that we can make available to our users to make their lives easier or even just a bit goofier. Think of all the strange secret functionality you can add to even your most static sites by adding a bit of logic using query parameters.
I've started building a concepting tool that uses these principles of links, parameters, and CSS variables that I'm very excited to write more about soon. If you're interested in discussing this topic or have built something with similar concepts, please reach out to share!