Fun with High-DPI displays

With the release of a lot of high-DPI displays (aka “retina” displays, but also others on both Android and iOS devices), it’s just a truism that images on these displays have tended to not look their best, all the time. High-DPI displays are having to scale up low-resolution images, and it’s just not great.

There is a simple solution for this, using either CSS or Javascript tricks, but the basic principle behind it is to make an image twice as big on each dimension (four times the area), and then let the browser scale it down into the space it’s supposed to fit into. This lets the high-DPI displays have more information to work with and to make images which scale much better. The problem, of course, is that larger images require more space and bandwidth. With various CSS and JS techniques, you can target it such that the high-res images are only sent to browsers that really need them, saving on the bandwidth.

Anyway, lately we’ve been making those sorts of changes to WordPress.org too. If you’re visiting on a high-DPI display, you may notice that the main header logo is of a higher quality, or you might have noticed that the Showcase looks particularly good, or that we now have some very high resolution images on the Logos and Graphics page. Little changes to the graphics, here and there. It’s an ongoing project to “retina-all-the-things”.

Back in December, we made some changes to allow plugin authors to put banner images above their plugins in the directory, and the response has been great. So, now they get the high-DPI love too.

Plugin authors already have the ability to make a banner-772x250.jpg or png file in their assets directory and have that be used for the banner image on their plugin listing. As of today, they can add a banner-1544x500.jpg or png file, for use on high-DPI displays only. When the website detects that the viewing browser both has a high-DPI display and the high-res image exists, then that image will be shown instead of the low-res image, but scaled to fit into the proper space. This makes them look particularly sharp on high-DPI displays.

Now, before you go forth and create, please remember that one thing to keep in mind here is filesize. If you’re using photographic material for your banner, then it is highly recommended that you use the JPG file format. If you’re using drawn or generated materials, PNG is the favored format. However, in either case, you will want to apply high compression and try to keep those files as small as possible. Small files transfer to the browser faster. Also consider that a fair number of high-DPI displays will be phones, for example, and perhaps not using high-speed connections. So keeping that high-res file as small as you can would be a good thing. If you wish to use a PNG compression tool before uploading, that might be a good idea as well.

And there you have it. Plugin authors, go forth, and show us your high-resolution banner skills!

BTW, if you want to see it, I gave my Pluginception plugin a high-res image, for testing. It’s a simple image with some well-defined lines that make the difference easy to spot if you’re looking for it. You’ll need a high-DPI display to see it though.

It’s not about resolution as much as it’s about pixel density. The new Macbook Pro, for example, has 220 PPI, giving the screen a resolution of 2880×1800. However, that resolution is clearly insane for a 15-inch screen, since you can’t see a pixel at that low of a size. So images have to be scaled up, and that’s where it falls apart.

See, if I have a page on a normal screen that looks good at 1600px across, then try to display the same thing on a screen that’s 2880px across, it’s either going to be tiny, or I have to zoom in, making one “pixel” in the image take up more than one “pixel” on the screen.

So, the trend is divorce the web “pixel” from the actual physical pixels on the monitor. If I make a 1000px wide image, but then use CSS to display it in a 500px wide space, then a browser on a very high-resolution monitor can recognize when the “500px” wide space is actually taking 1000 physical pixels on the screen, and thus properly display the high resolution image, while still fitting it properly into the webpage.

The keyword here is “device-pixel-ratio”. If one web “pixel” == one physical pixel, then the device-pixel-ratio is 1.0. On high DPI displays, the ratio may be larger. On a retina display, that ratio is 2.0. On my Samsung Galaxy SII, it’s 1.5.

The plugin banner space is 772px wide. If you’re displaying it on a device where the device-pixel-ratio is greater than about 1.5, then using the high-res image will give you more detail in the same space, and fit properly. On a retina display, you get all the detail, because 1 “web pixel” = 2 “physical pixels”.

Refresh a couple times, or visit the main front page of the site first. It won’t recognize your device the first time, until the cookie gets set for you. This is to prevent us from having to waste a lot of bandwidth by serving low-res images and then converting them to high res images. Most people will get recognized before navigating deeper into a high-image area.

For certain cases, I think I’ll probably look at optimizing the high-res images so that we can just use them always (if the filesizes are the same, then it doesn’t matter). Other cases can probably be converted to the CSS background approach, making JS unnecessary. I’m sure there’s further optimizations we can do.

There’s not much to post, really. Adding this was just a matter of hacking in a few lines of code. The plugin SVN system is originally derived from the bbPress SVN Tracker plugin (https://bbpress.org/plugins/topic/svn-browser/) and the code that isn’t in there is just a bunch of customizations specific to the wp.org plugin repository and the theme for displaying it and such. Adding a line to make it find assets like these and use them when needed is just some additional add-on bits to that theme, nothing particularly special about it.

Well, I see that you are setting a devicePixelRatio cookie, just like on Matt’s site, but the PHP thing which replaces the image URL must be something custom. Is that a cookie check on every request followed by “if_file_exists”?

Kaspars: Sort of. It is a cookie check at display time, but the file is only checked for during the scanning process which builds the plugin’s topic-page to begin with. I check for certain files and then add info about them to the topic-meta for the plugin’s topic. So it’s checking for a cookie, and then for the corresponding topicmeta. The cookie is site-wide, and used in a lot of places.

I’m not trying to solve this as a generic problem, I’m solving it for WordPress.org. A generic solution such as you’re suggesting would very likely work though. However, you’d need a generic way to both produce and name the high-resolution images for them to be found and served programmatically. I’d also be concerned about naming and proxy-caching by other systems, you’d likely want to redirect browsers to alternate URLs in case they’re behind a caching system of some sort. Having the same URL return two different things depending on a cookie (or user-agent sniffing) is a recipe for problems.

BYPASS means that it’s bypassing WordPress(.com) “full html” cache, based on the information in your request (likely cookie or useragent).
luv is the datacenter: Love Field Airport (DAL)
138 relates to which of the static caching servers it would have HIT, I believe.

For the vast majority of cases, I’m using pure CSS now. For edge cases, there’s a cookie that gets set with your device pixel ratio which we can use on the server side of things to determine which image to show you.