{"id":235423,"date":"2015-12-07T07:11:23","date_gmt":"2015-12-07T14:11:23","guid":{"rendered":"http:\/\/css-tricks.com\/?p=235423"},"modified":"2017-04-10T18:39:15","modified_gmt":"2017-04-11T01:39:15","slug":"the-blur-up-technique-for-loading-background-images","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/the-blur-up-technique-for-loading-background-images\/","title":{"rendered":"The “Blur Up” Technique for Loading Background Images"},"content":{"rendered":"

The following is a guest post by Emil Bj\u00f6rklund<\/a>. Filter effects in CSS have been around for a while, and together with things like blend modes, they bring new possibilities for recreating and manipulating stuff in the browser that we previously had to do in Photoshop. Here, Emil explores a performance technique using one of the more forgotten filter effects \u2013 the filter function<\/em> \u2013 as well as recreating it with SVG.<\/em><\/p>\n

<\/p>\n

This all starts with a post from the Facebook engineering team on how they load cover photo previews<\/a> in their native apps. The problem they faced is that these “cover photos” are large and often take a while to load, leaving the user with a less-than-ideal experience when the background suddenly changes from a solid color to an image.<\/p>\n

This is especially true on low-connectivity or mobile networks, which often leave you staring at an empty gray box as you wait for images to download.<\/p><\/blockquote>\n

Ideally the image would be encoded into the initial API response of their app when getting the profile data. But to fit inside this request, the image would have to be capped at 200 bytes<\/em>. Troublesome, as cover photos are over 100 kilobytes<\/em> in size.<\/p>\n

So how do you get something valuable out of 200 bytes and how do we show the user something<\/em> before the image is fully loaded? <\/p>\n

The (ingenious) solution was to return a tiny image (around 40 pixels wide) and then scale that tiny image up whilst applying a gaussian blur. This instantly shows a background that looks aesthetically pleasing, and gives a preview of how the cover image would look. The actual cover image could then be loaded in the background in good time, and smoothly switched in. Smart thinking!<\/p>\n

There are a couple of cool things about this technique:<\/p>\n

    \n
  1. It makes the perceived loading time wicked fast.<\/li>\n
  2. It uses something traditionally costly in terms of performance to increase performance<\/em>.<\/li>\n
  3. It\u2019s doable on the web.<\/li>\n<\/ol>\n

    Big header background images (and their performance drawbacks) are definitely something that we can relate to when building for the web, so this is useful stuff. We may try to avoid the downloading of heavy images, but sometimes we make the tradeoff to to achieve a certain mood. The best we can do in that situation is try to optimize the perceived performance, so we might as well steal this technique.<\/p>\n

    A working example<\/h3>\n

    We\u2019re going to recreate this header image feature with a sort of \u201ccritical CSS\u201d approach. The very first request will load the tiny image in inline CSS, then the high-res background comes after first render. <\/p>\n

    It will look something like this when it\u2019s done<\/em> loading:<\/p>\n

    <\/figure>\n

    In this example, we are using a background image, regarding it as decoration rather than part of the content. There are some finer points to debate around when these types of images are to be regarded as content (and thus coded as an <img><\/code>) and when they are background images. In order to make use of smart sizing modes (like the CSS values cover<\/code> and contain<\/code>), background images are probably the most common solution for these kinds of designs, but new properties like object-fit<\/code><\/a> are making the same approach a bit easier for content images. Sites like Medium<\/a> already use blurred content images to improve load times, but the usefulness of that technique is debatable \u2013 do the blurred images bring anything to the table if the loading technique fails? Anyway: in this article, we\u2019ll focus on this technique as applicable to background images.<\/p>\n

    Here\u2019s the outline of how it\u2019ll work:<\/p>\n

      \n
    1. Inline a tiny image preview (40×22 pixels) as a base64-encoded background image inside of a <style><\/code>-tag. The style tag also includes general styling and the rules for applying a gaussian blur to the background image. Finally, it includes styles for the larger version of the header image, scoped to a different class name.<\/li>\n
    2. Get the URL to the large image from the inline CSS, and preload it using JavaScript. If the script fails for some reason, no harm no foul \u2013 the blurred background image is still there, looking pretty cool.<\/li>\n
    3. When the large image is loaded, add a class name that toggles the CSS to use the large image as the background while removing the blur. Hopefully, the blur-removal part can also be animated.<\/li>\n<\/ol>\n

      You can find the final example as a Pen<\/a>. You\u2019ll likely see the blurred image for a moment before the sharper image loads. If not, try reloading the page with an empty cache.<\/p>\n

      A tiny, optimized image<\/h3>\n

      First of all, we need a preview version of the image. Facebook got the size of theirs down to 200 bytes via compression voodoo (like storing the non-changing JPEG header bits in the app), but we\u2019re not going to get quite that extreme. With a size of 40 by 22 pixels, this particular image comes in at around 1000 bytes after running it through some image optimization software.<\/p>\n

      <\/figure>\n

      The full-size JPEG image is around 120Kb at 1500 \u00d7 823 pixels. That file size could probably be a lot lower, but we\u2019ll leave that as is, since this is a proof of concept. In a real-world example, you would probably have a few size variations of the image and load a different one based on viewport size \u2013 heck, maybe even load a different format like WebP.<\/p>\n

      The filter<\/code> function for images<\/h3>\n

      Next, we want to scale the tiny image up to cover the element, but we don\u2019t want it looking pixelated and ugly. This is where the filter()<\/code>-function comes in. Filters in CSS might seem a little confusing, as there are effectively three kinds: the filter<\/code> property, its proposed backdrop-filter<\/code> counterpart (in the Filter Effects Level 2 spec<\/a>) and finally the filter()<\/code> function for images. Let\u2019s take a look at the property<\/em> first:<\/p>\n

      .myThing {\r\n  filter: hue-rotate(45deg);\r\n}<\/code><\/pre>\n

      One or more filters are applied, each operating on the result of the previous \u2013 a lot like a list of transforms. There\u2019s a whole range of predefined filters<\/a> that we can use: blur()<\/code>, brightness()<\/code>, contrast()<\/code>, drop-shadow()<\/code>, grayscale()<\/code>, hue-rotate()<\/code>, invert()<\/code>, opacity()<\/code>, sepia()<\/code> and saturate()<\/code>.<\/p>\n

      What\u2019s even cooler is that this is a spec shared between CSS and SVG, so not only are the predefined filters specced in terms of SVG, we can also create our own filters in SVG and reference them from CSS:<\/p>\n

      .myThing {\r\n  filter: url(myfilter.svg#myCustomFilter);\r\n}<\/code><\/pre>\n

      The same filter effects are valid in backdrop-filter<\/code>, applying them when compositing a transparent element with its backdrop \u2013 perhaps most useful for creating the \u201cfrosted glass\u201d effect<\/a>.<\/p>\n

      Finally, there\u2019s the filter()<\/code> function for image values. The idea is that anywhere that you can reference an image in CSS, you should also be able to pipe it through a list of filters. For the tiny header image, we inline it as a base64 dataURI and run it through the blur()<\/code> filter.<\/p>\n

      .post-header {\r\n  background-image: filter(url(data:image\/jpeg;base64,\/9j\/4AAQ ...[truncated] ...), blur(20px));\r\n}<\/code><\/pre>\n

      This is great, since this is exactly what we\u2019re looking for when recreating the technique from the Facebook app! There\u2019s bad news on the support front though. The filter<\/code> property<\/em> is supported in the latest versions of all browsers except IE, but none of them except WebKit<\/a> have implemented the filter()<\/code> function<\/em> part of the spec.<\/p>\n

      When I say WebKit here, I mean the WebKit nightly builds at the time this post is written, and not Safari. The filter<\/code> function for images is<\/em> technically in iOS9 as -webkit-filter()<\/code>, but this hasn\u2019t been reported anywhere official as far as I can find, which is a bit weird. The reason is probably that it has a horrible bug<\/a> with background-size<\/code>: the original image is not resized, but the filtered output tile size is. This breaks background image functionality pretty bad, especially with blurring. It has been fixed, but not in time to make it into the Safari 9 release, so I guess they didn\u2019t want to announce that feature.<\/p>\n

      But what do we do with the missing\/broken filter()<\/code> functionality? We could either give browsers that don\u2019t support it a solid background until the image loads, although that means they\u2019ll get no background at all if JS fails to load. Boring!<\/p>\n

      No, we\u2019ll save the filter()<\/code> function as an extra spice for animating the swapped-in image later, and instead emulate the filter function for the initial image with SVG.<\/p>\n

      Recreating the blur filter with SVG<\/h3>\n

      Since the spec handily provides an SVG equivalent for the blur()<\/code>-filter<\/a>, we can recreate how the blur filter works in SVG, with a few tweaks:<\/p>\n