Patching Up
2025-11-06
After my last post about this blog, I thought it was in rather good shape! Then, just as I was to hop off to bed, I decided to see what the real mobile experience was like, and dang, it's a terrible mobile experience.
Why is everything so small??
As I opened up my homepage, I immediately found it hard to even hit any of the links that send me to an actual post. Luckily, the scaling fixes itself (sort of) the moment a post is opened. Why???
I had set up fonts to have a height of 16-18 pixels, so why did it look like it was set to 4 pixels? As it turns out, the viewport width is generally 980px by default (in portrait orientation), no matter the device. This seems to have been a choice made when smartphones became a thing to avoid websites from being completely smushed up when viewed on mobile (try cranking up the zoom on a website to 500% and you can see how usability issues arise).
Also, to make things even more confusing, it turns out the "px" unit in CSS is a "CSS Pixel", which is defined by "1/96th of an inch", not actually a pixel on your screen. Well, actually, this makes some sense to me since display resolutions have only gotten higher, so it would be weird if websites got smaller every time you upgraded your phone.
Anyway, courtesy of a stack overflow answer, it seems the solution to this is just as simple as adding the following into the website header:
<meta name="viewport" content="width=device-width, initial-scale=1">
Problem solved!
Also, from a reddit comment, I found out that setting the padding to 1rem might be a better idea than 1ch.
Bonus Section: Firefox Setup
As it turns out, for testing mobile viewing on desktop, Firefox has a nifty tool called "Responsive Design Mode", which is accessible via the hamburger menu -> More Tools -> Responsive Design Mode. Alternatively, the shortcut "Ctrl + Shift + M" also does the trick.
Optimization
Another thing I realized was that now that I have a functional webpage, I can finally pass in my website to PageSpeed Insights!
Reducing Font Size
Although I thought that 378 KiB was small for a font, it turns out I'm wrong. In fact, it seems like the downloading of the Inter font appears to be the main bottleneck when rendering the site. I'm already using the WOFF2 format, which is already compressed, so further compression here is not ideal. The next best thing I found is font subsetting, which basically means removing unused glyphs from the font being used.
For this, I had a few requirements:
- For the glyphs, only keep latin glyphs and punctuation, maybe a few others.
- Keep everything else (metadata and ligatures)
I tried quite a few tools, such as:
- FontSquirrel
- This is a web-based tool for subsetting fonts.
- Two weird things prevented me from using this tool properly. Firstly, it didn't support importing a WOFF2 file to use as the font to subset (which was weird because it "supports" exporting the subset as a WOFF2 file). Secondly, upon exporting the document, I get a zip file containing a bunch of other files, but not the font subset itself.
- Transfonter
- Like FontSquirrel, this is another web-based tool for subsetting fonts. This almost worked. It was much faster than FontSquirrel, and it did return a usable font. It even kept all the ligatures and metadata! Unfortunately, it doesn't seem to support variable fonts, which is unfortunately a dealbreaker as I would like to avoid using multiple fonts for multiple weights (bold, headers, etc).
- Glyphhanger
- This tool has a nice feature that allows the user to subset a font based on the glyphs found on a webpage, and it can even seach multiple pages with a
--spiderflag! - Unfortunately, the setup to get the
--spiderflag working involved getting a bunch of dependencies for puppeteer, which is what I'm assuming it uses to crawl webpages. Although, that is partially my fault for running it in a weird environment (a Fedora 43 Toolbox). For future reference, the missing dependencies were:alsa-lib,libasound,libXrandr,libXdamage,libXcomposite,libxkbcommon- and to get
brotliandzopfliworking,gccandg++are required
- After getting web crawling to work, Glyphhanger still couldn't crawl all the pages of my site properly, which left some characters with the default fallback font (or maybe I didn't use the tool correctly).
- Furthermore, when examining the subset font, I also noticed that it striped the licensing metadata (which I think is against the OFL).
- Turns out that using the
--jsdocflag fixes the page crawler, so now we aren't missing any fonts. However, after checking the contents of the font with FontDrop, I feel like there are still quite a few glyphs that can be culled.
- This tool has a nice feature that allows the user to subset a font based on the glyphs found on a webpage, and it can even seach multiple pages with a
I eventually landed on pyftsubset, is the tool being used behind the scenes in Glyphhanger. I figured I could get a bit more control over the output by just using it directly, and I finally got it to subset as I expected.
I used the unicode range given to me by Glyphhanger, which was created by scanning my blog and including the US_ASCII range as well to slightly future-proof the subset. This is the final command I ended up using:
pyftsubset InterVariable.woff2 \
--output-file=./InterVariable-subset.woff2 \
--flavor=woff2 \
--unicodes=U+20-7E \
--desubroutinize \
--name-IDs=*
Let's also break it down quickly.
InterVariable.woff2- The input font. Of course, I'm calling this command from the directory that contains the font.
--output-file=./InterVariable-subset.woff2- The filepath of the output subset font. I set it to just create a file called
InterVariable-subset.woff2in the current directory.
- The filepath of the output subset font. I set it to just create a file called
--flavor=woff2- Declaring the output font format to be WOFF2.
--unicodes=U+20-7E- Declaring the range of unicode characters to keep in the subset.
--desubroutinize- According to the documentation, setting this flag may allow the subset files to be compressed better, but I don't really see any difference. Either way, there was minimal impact on runtime, so no harm done.
--name-IDs=*- This just tells the program to keep all the Name IDs.
- NameIDs are basically the font metadata. It's a table consisting of a numerical ID and a field, and the specification of this table can be found here.
- By default, pyftsubset only keeps IDs 0-6, which means the font license, ID 13, is omitted by default. Keeping all Name IDs naturally preserves the font license.
Through this process, I'm left with a nice font subset that is about 40 KiB, which is a 88% size reduction compared to the original 344 KiB. Fantastic!
A quick PageSpeed mobile test shows us that we've gone from a performance score of 89 to 99! Unfortunately, there are still some small accessibility and SEO problems, but I'll get around to that another time.