← All writing
Craft · · 7 min

The CMS undoes it

A hero image that grew 13 times over, four months after I handed the site off.

Images Performance WordPress

I went back to a site I shipped in January because I wanted a screenshot of it for something, and the homepage took a noticeable moment to draw on my own broadband.

The hero image was 2.4 MB. I shipped that page with a 180 KB hero. I remember, because I’d been quite pleased with it.

What had happened is not a mystery and is not anybody’s fault. There was a summer campaign, the client swapped the hero, and the file they swapped it for came straight out of the photographer’s Dropbox at 4,000 pixels wide. The CMS accepted it, scaled it to fit the slot, and served it. The system worked exactly as designed.

This is the mild version. On the stores it’s not one hero a merchandiser swaps in June, it’s 4,000 product shots uploaded by whoever is doing the catalog that week, and no one person ever sees the aggregate.

Six weeks mine, four years theirs

I own a site for about six weeks. They own it for four years.

Everything I do at build time is a snapshot of a decision, and every one of those decisions is available to be re-made by someone else, later, in a hurry, through an interface I built. My gulpfile runs imagemin over every asset in the project. My gulpfile is on my laptop. It has never run on their server and it never will.

So the performance work I did in January wasn’t wrong, it just had a shelf life that I hadn’t thought about at all, and the shelf life was “until the first time anything changes.”

The deliverable was never a fast site. It was a site that's difficult to make slow.

Four sizes, none of them small

Worth being specific, because the modern CMS looks like it’s helping and is helping about 40% as much as it appears to.

WordPress has generated responsive images automatically since 4.4, which is genuinely good and I was pleased when it landed. You upload one file and it writes a srcset for you off the sizes it generated. Here’s what that looked like for the summer hero:

wp-content/uploads/2016/06/
hero-summer.jpg             4000x2667    4.8 MB   <- the original, still linked
hero-summer-1024x683.jpg    1024x683     412 KB
hero-summer-768x512.jpg      768x512     241 KB
hero-summer-300x200.jpg      300x200      48 KB

Four sizes, correct markup, sizes attribute present. And every one of those is a re-encode of a 4.8 MB original at the default quality, with the camera’s metadata still in it, and not one of them has been near a compressor. The largest generated size is 412 KB doing the job my 180 KB file was doing, and on a wide screen it was serving the original anyway.

Death by a thousand plugins

Once I started looking, images were only the loudest one.

The editor. Two months of a WYSIWYG and the body copy has inline styles in it, an <h1> halfway down a page because it looked the right size, and text that’s bold where it should be a heading. Which is the accessibility version of the same problem, and also the reason the style guide I built for that site describes components that three pages no longer use.

Plugins. A client installed a slider because they wanted a slider, and it arrived with its own copy of jQuery, an icon font I was already loading a different icon font instead of, and a Google Font in a weight nothing on the site uses. That’s not a criticism of the client. They were given an interface with a button on it that says install, and it worked.

Tags. Marketing adds a tag manager, the tag manager loads four things, and I have spent a day of my life fighting for 90 KB that were then outbid by somebody in a different meeting who never knew there was an argument. I don’t have a good answer to that one and I’m not sure it’s a technical problem at all.

Things that outlive me

Roughly in order of how well they hold up.

Move the processing to the server. Resize on upload, re-encode, strip the metadata, cap the longest edge at something sane. Whether that’s a plugin, a hook, or an image CDN sitting in front of the whole thing matters much less than the fact that it isn’t optional and it isn’t on my machine. This is the only thing on the list that works whether or not anyone remembers it exists, which is the property I’m actually after.

Constrain the upload. Refuse the 4.8 MB file, with a message that says why and what to do instead. I resisted this for ages because rejecting a person’s file feels hostile, and then I watched somebody upload the same photo four times wondering why the page was slow, and decided that silently accepting it was the more hostile option.

Restrict the editor. Take out the formatting controls that produce things your CSS doesn’t support. If there’s no color picker there’s no pink heading, and nobody has ever complained to me about the absence of a color picker. They complain about the site looking messy, which is the same complaint arriving from the other end.

And a number somebody watches. Weakest of the four because it depends on a human noticing, but a monthly check on the homepage weight has caught two of these for me and it costs nothing to set up.

It’s their site, though

There’s a version of this post that’s just me wanting to lock the client out of their own website, and I want to take that seriously because I think it’s half right.

It is their site. They paid for it, they run their business on it, and a developer deciding they can’t be trusted with an upload form is exactly the paternalism that makes people hate their agency. I’ve been on the receiving end of somebody else’s clever constraint and it’s infuriating when nobody explains it.

Two things I’d say back. The first is that a constraint you agreed to in advance is a completely different object from one you discovered by being blocked, so the work is in the conversation, not the code. “We’ll cap uploads at 2000 pixels because a photo bigger than that makes the page slow on phones and doesn’t look any better” is a sentence every client I’ve said it to has agreed with immediately.

The second is that these constraints mostly make their job easier, not harder. Nobody in a marketing team wants to think about JPEG quality settings. They want to put the summer picture on the website and have it look right, and every decision I take off their plate is one they were never being paid to make either.

A duller ambition

The thing I actually changed after that screenshot wasn’t the hero. It was that I now write down, at the start of a project, the list of things a person will be able to do to this site after I’ve gone, and then ask which of them can break it. It’s a short list and it takes 20 minutes and it would have caught this one in January.

I’d previously thought of my job as making a fast site. It’s closer to making a site where the slow option isn’t available. Duller ambition, much more durable.

Read similar posts
6 min

srcset, revisited

The exact bug I wrote about in 2018, on a site built last year, by a competent team, with a modern pipeline. Which tells you which parts of this got fixed in eight years.

9 min

Just look at it

Most image optimization advice is about codecs, but the actual bug is usually that nobody has opened the file and looked at it since the day it came out of Figma.