Web dev at the end of the world, from Hveragerði, Iceland

The Curious Case Of The Crashing Conic Gradient And How I Used A Technique I Learned In The 90s To Fix It

Yesterday I published a new blog post of mine. I wrote a tongue-in-cheek retrospective list where I looked back over the past 23 years of web development and tried to boil down everything important into pithy aphorisms.

136 facts every web developer should know before they burn out and turn to landscape painting or nude modelling

Some of the aphorisms ended up not-so-pithy, but it was overall a fun little experiment that I recommend: note down everything relevant about the craft that you can think of over the space of a week.

As soon as I published the blog post, though, I started getting very curious reports. The site crashed in Firefox.

What made this particularly curious was that I do most of my web dev in Firefox—even my blog posts. The site doesn’t use any JavaScript, and the CSS is not particularly complicated.

How was this post suddenly crashing Firefox?

I ran off to test it in all of the Firefoxes that I had. It was fine in macOS. Windows was okay. Fine in Firefox Mobile on ChromeOS. But it crashed on Firefox Mobile on an Android phone.

And, I got a report that it was also crashing on Firefox on macOS M1.

But only that blog post, which is also on the front page. Other pages don’t crash these versions of Firefox.

Interesting.

I began by checking to see whether it was still crashing in Firefox Nightly on Android. It wasn’t, which meant that it looked like this will be fixed in an upcoming version, meaning I don’t have to bother with a bug report.

I also got a report that an earlier version of Firefox (81) wasn’t crashing. Which meant one of two things: either the crasher was a regression in an older feature or that the bug was in a new feature. That made CSS the most likely culprit as I’m not using any JS, and the HTML I’m using has been around for years.

But, just in case, I tried splitting the long list in the blog post into smaller lists. You never know if you’ve just hit some weird edge case in memory handling or something. That didn’t fix it.

Remember, this is a new design, so most of the CSS on the site is fresh, and I was deliberately trying out new CSS to get a feel for how many of these new (ish) features work. It could have been anything.

The next step was to get a test setup up and running on my Android phone. The simplest way to do this is to use ngrok to make the localhost version of the site available over the web.

Testing crashers is especially tricky as the dev console is useless, and core dumps are opaque as hell.

So, I used a trick I learned when figuring out which extension was crashing my Mac back in the Mac Classic/System 7-9 days.

For those who aren’t old as dirt, like me, back before OSes had proper multitasking, a single piece of software could easily take down the entire system. When that single piece of software was an extension loaded on startup, and you had dozens of them loaded, figuring out which one was the culprit was a pain in the ass.

What you did was you started by disabling them all.

If your system booted, then you knew it was an extension issue.

Then you enabled half of your extensions.

If the system loaded, then you knew the problem was in the other half:

  • Load the other half.
  • If the system crashes, you disable half of those extensions and boot again.
  • If it still crashes, then you’ve narrowed it down to the current quarter of your extensions.
  • If it doesn’t crash, it’s in the other quarter.

Usually, once you’ve narrowed it down by 75% or so, a likely culprit will emerge. This is what makes this method a much quicker way of finding problem extensions than disabling them all and then adding them back, one by one.

Applying this method to CSS is simple, especially if you write your CSS in small files that you then concatenate into a single file for deployment.

  • Disable them all
  • Add back half
  • Either try the other half, if it didn’t crash, or remove half of this batch if it did
  • Continue until you’ve ruled out 75% of your CSS. Then review the rest to see if you can spot a likely suspect.

The first round of testing ruled out font-related CSS as a source of the issue and the second round narrowed it down to the styling of the blog post container.

I took a look at the CSS for that class, and the only new CSS feature I was using in that file was conic-gradient.

Once I removed that, the post started to load again in Firefox for Android.

What was happening was that whenever Firefox tried to create a conic gradient over a certain size, it bumped up against a memory limit somewhere (probably platform-specific) and crashed.

conic-gradient was introduced in Firefox 83, which explains why version 81 wasn’t crashing.

I had used a conic-gradient background because it looked a little bit less regular than a linear-gradient. Disabling it, while a bit sad, wasn’t a hardship.

Most people won’t notice the difference.

That was the curious case of the crashing conic gradient: how a new CSS feature managed to blow Firefox out of the water and how I used a technique I learned in the 90s to fix it!

You can also find me on Mastodon and Twitter