What the CMS does to your hero image
I went back to a site I launched in January because I wanted a screenshot of it for something else, and the homepage sat there for a beat before it drew anything. On my own broadband, on a laptop, plugged into a wall.
The hero image was 2.4 MB. I launched that page with a 180 KB hero and I remember being fairly pleased with myself about it.
What happened isn’t a mystery and isn’t anybody’s fault. There was a summer campaign, somebody swapped the hero for it, and the file they swapped in came straight out of the photographer’s Dropbox at 4000px wide. The CMS took the file, scaled it into the slot, and served it. The interface worked exactly the way it was built to work.
Now with four sizes
I didn’t expect the CMS to have already tried to help.
WordPress has generated responsive images by itself since 4.4 landed in December, which is genuinely good and I was happy about it at the time. You upload one file, it makes a few smaller copies, and it writes the srcset for you off what it made. Here’s what it made for the summer hero.
hero-summer.jpg 4000x2667 2.4 MB <- still in the srcset
hero-summer-1024x683.jpg 1024x683 412 KB
hero-summer-768x512.jpg 768x512 241 KB
hero-summer-300x200.jpg 300x200 48 KB
Four files, correct markup, sizes attribute present and everything. And every one of those is a re-encode of the original at whatever the default quality is, none of them has been near a compressor, and the biggest one is 412 KB doing the job a 180 KB file was doing in January. WordPress also puts the full-size original in that srcset, so on a wide screen it skipped all of its own work and handed over the whole 2.4 MB.
So the automation I’d been asking for arrived. It arrived set to whatever somebody at Automattic picked as a reasonable guess about a site they will never see.
I had already written this post
I own a site for about six weeks. The client owns it for years after that.
Everything I do at build time is a snapshot of a decision, and every one of those decisions sits there waiting to be re-made by somebody else, later, in a hurry, through an interface I built for them. 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.
I wrote a post last fall that ends by saying the only version of this that survives is the one in the pipeline, resizing on upload, a quality setting, unglamorous infrastructure that keeps working while nobody is paying attention. Then I launched a site in January and put the optimizer in my gulpfile. I don’t have a good explanation for that. I think I read my own conclusion as a thing I now understood instead of a thing I now had to go build.
So the performance work in January wasn’t wrong. It had a shelf life I hadn’t thought about even once, and the shelf life turned out to be “until somebody changes something.”
It came with friends
Once I started looking, the images were only the loudest one.
The editor. A couple months of a WYSIWYG and the body copy has inline styles baked into it, an <h1> halfway down a page because it was the size somebody wanted, and text that’s bold where it should be a heading. That last one is the same problem I ran into with alt attributes in February, arriving from a different direction. The field accepted what it was given, the page looks fine, and the thing that’s wrong with it is invisible unless you go and look. This is what it looks like at a couple months. Four years of it is a line item in a redesign, which I watched land on a different project in May and somehow filed as that project’s problem.
Plugins. Somebody installed a slider because they wanted a slider. 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. Which is not a criticism of anybody. They were handed an interface with a button on it that says Install, and the button installed it.
Nobody has to remember
Four things I’d do differently, roughly in order of how well they hold up.
Move the processing to the server. Resize on upload, re-encode at a sane quality, cap the longest edge at something the design actually uses. Whether that’s a plugin, a hook, or an image CDN sitting in front of the whole site matters much less than the fact that it isn’t optional and it isn’t on my machine. This is the only one on the list that works whether or not anybody remembers it exists, which is the property I’m actually after.
Constrain the upload. Refuse the 2.4 MB file, with a message that says why and what to do instead. I resisted this one for a long time because rejecting a person’s file feels hostile, and then I watched somebody upload the same photo over and over wondering why the page was slow, and decided that quietly accepting it was the more hostile option.
Restrict the editor. Take out the formatting controls that produce things the 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 that the site looks messy, and that is the color picker, one step downstream.
And a number somebody watches. Weakest of the four, because it needs a human to notice, but a monthly look at what the homepage weighs has caught two of these for me and it costs nothing to set up.
Who died and made me the arbiter
There’s a version of this post that’s just me wanting to lock a client out of their own website, and it’s about 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 well-meant constraint and it is infuriating when nobody explains it.
Two things I’d say back though. (1) 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 and not in the code. “We’ll cap uploads at 2000px, 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 on the spot. And (2) most of these make their job easier instead of harder. Nobody on 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 in the first place.
The list I write at the start now
The thing I actually changed after that screenshot wasn’t the hero.
At the start of a project I now write down the list of things a person will be able to do to this site after I’ve gone: change the pictures, edit the copy, add a page, install something. Then I go down it asking which ones can break it. It’s a short list, it takes about 20 minutes, and it would have caught this one in January.
I used to think of the job as making a fast site. It’s closer to making a site where the slow thing isn’t the easy thing to do, which is duller to be good at and holds up a lot longer. The person who swapped that hero was doing their job well. They had a campaign to get up, a picture that looked great, and a form that took the picture without complaining, and nothing anywhere in that sequence had any reason to tell them otherwise. Building the thing that tells them is my job, and it isn’t a job I can do in January with a gulpfile.