WordPress Images

Why Your Images Look Soft on a Retina Screen, and What srcset Really Does

The file is fine. The screen is drawing more dots than you supplied.

Two different things are called a pixel, and the gap between them is why a perfectly good photograph turns faintly blurry on a modern phone.

An image menu with resize and canvas size options

You upload a crisp photograph, it looks perfect on your laptop, and then somebody opens the site on a modern phone and the picture is faintly soft. Not broken, not obviously wrong, just slightly out of focus in a way you cannot quite point at.

Nothing is wrong with the file. The screen is simply drawing more dots than the image has pixels, and the browser is making them up.

Two different things called a pixel

The confusion at the heart of this is that the word pixel means two different things.

A device pixel is a physical dot on the screen. A CSS pixel is a unit of layout, roughly the size a dot used to be on an old monitor, kept as a reference so that a 300 pixel wide box stays about the same physical size everywhere.

On an old display these matched. On a modern phone one CSS pixel is drawn with two or three device pixels in each direction. The ratio is the device pixel ratio, and it is why a photograph placed in a 400 CSS pixel wide slot may actually need to fill 800 or 1200 real dots.

Supply 400 pixels of image data and the browser has to invent the rest by interpolation. Interpolation is a polite word for guessing, and guessing looks soft.

The fix, and why it is not simply “upload bigger”

The obvious response is to upload everything at three times the size. That fixes sharpness and breaks something else: the phone with the dense screen is usually the device on the slowest connection, and you have just tripled what it downloads.

What you actually want is different files for different situations, with the browser choosing. That is what the srcset attribute is for, and WordPress has generated it automatically for years, which is why most sites get this roughly right without anyone doing anything.

Roughly right, not right. It is worth knowing where it falls down.

What srcset and sizes actually say

Two attributes, doing two different jobs, and mixing them up is the usual cause of trouble.

srcset is a menu: here are the versions of this image that exist, and here is how wide each one is in real pixels. It is a statement of fact about your files.

sizes is a promise: here is how wide this image will be displayed, at various viewport widths. It is a statement about your layout.

The browser reads the promise, multiplies by the device pixel ratio, and picks the smallest entry from the menu that meets or exceeds the result. Crucially it does this before the stylesheet has necessarily been applied, which is why it has to be told rather than measuring.

And that is where it goes wrong: WordPress cannot know your layout, so it guesses a default like “this image will be as wide as the viewport”. If your image actually sits in a 700 pixel column, every visitor downloads a file far larger than needed. The information is not wrong, it is simply a promise nobody kept.

An image menu with image size, canvas size and resize options
Deciding the largest size an image will ever be displayed at is a design decision. Everything downstream follows from it.

Registered sizes, and the ceiling nobody notices

WordPress creates copies of every upload at a set of registered sizes. Those copies are what fills the menu. If the largest registered size is 1024 pixels wide, then no matter how large your original is, a hero image spanning a wide desktop screen at a device pixel ratio of two has nothing suitable to choose and falls back to something too small.

Two things follow. First, check what sizes your theme actually registers, because the answer is often surprising. Second, if you have a full width hero, make sure something exists at 2000 pixels or more, and make sure it is well compressed, because it is a big file that many visitors will download.

There is a matching trap at the other end. WordPress skips generating a size if the original is smaller than it, so uploading a 900 pixel image where the layout needs 1600 produces no error and no large version. It just looks slightly soft forever.

Different images, not just different sizes

Everything above assumes the same picture at different resolutions. Sometimes that is not what you want.

A wide landscape photograph that works beautifully as a desktop banner becomes a thin strip on a phone, with the subject reduced to nothing. The answer is not a smaller version of the same crop, it is a different crop: a squarer or portrait version where the subject still fills the frame. That is art direction, and it needs the picture element rather than srcset, because you are switching images rather than resolutions.

It is more work, so save it for the images that carry weight: the hero, the product shot, anything where the composition is the point.

Where the soft look really comes from

Resolution is only half the story. Three other things soften an image, and they are easier to fix.

Resizing without sharpening. Every downscale loses fine detail; that is what downscaling is. Professional workflows always finish with a small amount of sharpening after the resize, tuned to the final size. Skip it and the image looks slightly veiled even at the correct dimensions.

Compression at the wrong point. Fine detail is exactly what lossy compression discards first. An image at quality 60 will look soft at any resolution.

CSS scaling. An image sitting in a container that is not an exact multiple of its natural size gets resampled by the browser, which is fast rather than good. Odd fractional widths are a common cause.

A view menu with zoom controls including a one hundred per cent option
Judging sharpness at anything other than one hundred per cent is judging the zoom algorithm, not the picture.

A practical checklist

  1. Work out the widest a given image will ever be displayed, in CSS pixels.
  2. Double it. That is the largest version you need; going to three times is rarely worth the bytes.
  3. Make sure a registered size exists at that width, and that your originals are at least that large.
  4. Correct the sizes attribute for images that sit in a fixed column, rather than accepting the default.
  5. Sharpen after resizing, gently, at the final size.
  6. Check at exactly 100 per cent zoom, on an actual dense screen if you have one.

The one line worth remembering

Supply about twice the pixels the layout asks for, compress them properly, sharpen after resizing, and tell the browser the truth about how wide the image will be. Everything else is detail.

Table of Contents

Learn it by building something

Every week one thing you can make the same afternoon, from dynamic templates to 3D type. Written down step by step.

One mail a week, and then it ends.
Unsubscribe in one click.

Free

Chaos Art

Autonomous painters make one-of-a-kind abstract art in 3D space - gestures, art movements, painterly media, and embeds that paint a new original for every visitor.

Download the free WunderPaint Plugin for WordPress

The Image Editor & Design Studio

Everything described here can be done in the browser, on your own site. The live demo runs the full editor with nothing to install.

Design Tools

Brush & Paint Styles

Paint with six styles that mix pigment instead of blending it, pick from thirty-seven tips shown as real strokes, draw a tip of your own out of shapes, and let the color travel along the stroke.

Workflow & Automation

Dynamic Templates: Build the Design Once, Let Your Posts Fill It In

You build the layout once, tell a few layers where to get their content, and from then on every post, product or page renders its own version.

Print & Craft

Making Things That Fold: Dielines, Duplex and Why Previews Matter

A gift box, a paper crane, a bunting banner. They look simple, and they fail in ways flat design never does, because there is a second geometry underneath.

WordPress Images

Why Should a Design Become a File at All?

Every static graphic on a page is a snapshot of what was true when somebody exported it. There is a whole category of quiet wrongness that follows from that.