138

To reduce the number requests on the server I have embedded some images (PNG & SVG) as BASE64 directly into the css. (Its automated in the build process)

like this:

background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAFWHRTb2Z0d2FyZQBBZG etc...);

Is this a good practice? Are there some reasons to avoid this? Are there some major browser that don't have data url support?

Bonus question: Does it make sense to do this for the CSS & JS also?

meo
  • 30,872
  • 17
  • 87
  • 123
  • 1
    not many people use IE7 anymore and for all the downsides there is a really good upside -- less image files to manage! i.e. if you need to draw special lines for a tree component then embedding the tiny elbow images in the css itself in combination with repeat-x or repeat-y removes the need for making sure extra image files are in the right place (with very little overhead for this use case) – DaveAlger Mar 20 '13 at 22:19

7 Answers7

161

Is this a good practice? Are there some reasons to avoid this?

It's a good practice usually only for very small CSS images that are going to be used together (like CSS sprites) when IE compatibility doesn't matter, and saving the request is more important than cacheability.

It has a number of notable downsides:

  • Doesn't work at all in IE6 and 7.

  • Works for resources only up to 32k in size in IE8. This is the limit that applies after base64 encoding. In other words, no longer than 32768 characters.

  • It saves a request, but bloats the HTML page instead! And makes images uncacheable. They get loaded every time the containing page or style sheet get loaded.

  • Base64 encoding bloats image sizes by 33%.

  • If served in a gzipped resource, data: images are almost certainly going to be a terrible strain on the server's resources! Images are traditionally very CPU intensive to compress, with very little reduction in size.

AaronLS
  • 37,329
  • 20
  • 143
  • 202
Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • does the size bloats even if the content is gzipped? – meo Mar 10 '11 at 10:07
  • 2
    @meo interesting point. I expect this is bad for gzip performance, as images are usually very optimally compressed already. Compressing them costs horrible amount of CPU space for single-digit percent gains. Try gzipping a JPG file and you'll see what you mean. I'll edit that into the answer – Pekka Mar 10 '11 at 10:09
  • 1
    i know that gzipping compressed images is not the way to go. But i was thinking that maybe its more effective on the base 64. Especially when you have more then one image in the source. – meo Mar 10 '11 at 10:12
  • 2
    @meo nope, it will not be more effective on the base64 under any circumstance, because the underlying patterns will still be the compressed image data that just happens to be expressed in base64 notation. – Pekka Mar 10 '11 at 10:12
  • thanks a lot! Do you have any thoughts about the bonus question to? – meo Mar 10 '11 at 10:22
  • @meo I don't understand what you mean there, can you clarify what you mean by "the CSS & JS"? – Pekka Mar 10 '11 at 10:22
  • you can include JS & CSS files as data: also. I was wondering if it makes sense there. src: http://www.greywyvern.com/code/php/binary2base64 – meo Mar 10 '11 at 10:24
  • 1
    @meo ah, I see. That won't work in IE at all, and has the same cacheability problem: You save a request, but every page request grows in size. It's usually probably much better to compact everything into one CSS, and one JS file – Pekka Mar 10 '11 at 10:26
  • ok i so i can give you the right answer with a +1 for the bonus question :) thank you – meo Mar 10 '11 at 10:33
  • There are some situations when there is almost no other way as to embed images as base64. For example, app_offline.htm on IIS. If you want to customize it, you have to embed images or else IIS will server the same app_offline.htm for every image request. But I guess, app_offline is a really special case. – JustAMartin Nov 29 '12 at 16:31
  • 6
    It does __NOT__ bloat the HTML page when you are embedding the images in a CSS file as the question indicates. – Daniel Beardsley Jan 03 '13 at 22:04
  • @Daniel then it bloats the CSS file. Arguably less of a problem than the HTML page, but to what end? – Pekka Jan 04 '13 at 10:58
  • Hi Pekka, is there no IE7 and IE6 workaround at all? And is there any workaround for the 32 KB size limit in IE8? – SexyBeast Feb 13 '13 at 15:19
  • 1
    According to this question (which seem to be similar or the same) http://stackoverflow.com/q/1124149/981933 your images are cached as the CSS file get cached. @Pekka웃 Could you tell us why you believe base64 encoded content is not cacheable? – F Lekschas Nov 08 '13 at 02:45
  • 1
    @Flek by embedding an image in the CSS style sheet, it can no longer be cached as a separate resource. Whenever anything changes in the style sheet, the entire file (including the image) has to be reloaded, while if you keep things separate, the CSS style sheet will usually be only a couple of kilobytes big. – Pekka Nov 08 '13 at 03:27
  • 1
    Note about gzip: gzipping the data uri **is** effective, and typically removes most of the 37% overhead due to base64. – spectras Dec 11 '18 at 19:51
42

Common answers here seems to suggest this is not needed, for a set of legit reasons. However, all of these seems to neglect modern apps behavior and build process.

It's not impossible (and actually quite easy) to design a simple process that will walk through a folder images and will generate a single CSS with all the images of this folder.

This css will be fully cached and will dramatically reduce round trips to the server, which is as correctly suggest by @MemeDeveloper one of the biggest performance hits.

Sure, It's hack. no doubt. same as sprites are a hack. In perfect world this will not be needed, until then, it's a possible practice if what you need to fix is:

  1. Page with multiple images that are not easily "spritable".
  2. Round trip to servers are an actual bottleneck (think mobile).
  3. speed (to the milliseconds level) is really that important for your use case.
  4. You don't care (as you should, if you want the web to go forward) about IE5 and IE6.

my view.

0xc0de
  • 8,028
  • 5
  • 49
  • 75
JAR.JAR.beans
  • 9,668
  • 4
  • 45
  • 57
  • 4
    This should be upvoted to get more attention. other answers are kinda obsolete -they talk about IE6 while IE8 is kinda obsolete these days... (and thanks for that) – Hertzel Guinness Jul 22 '14 at 10:05
10

It's not a good practice. Some browsers are not supporting data URIs (e.g. IE 6 and 7) or support is limited (e.g. 32KB for IE8).

See also this Wikipedia article for complete details on the Data URI disadvantages:

Disadvantages

  • Data URIs are not separately cached from their containing documents (e.g. CSS or HTML files) so data is downloaded every time the containing documents are redownloaded.
  • Content must be re-encoded and re-embedded every time a change is made.
  • Internet Explorer through version 7 (approximately 15% of the market as of January 2011), lacks support.
  • Internet Explorer 8 limits data URIs to a maximum length of 32 KB.
  • Data is included as a simple stream, and many processing environments (such as web browsers) may not support using containers (such as multipart/alternative or message/rfc822) to provide greater complexity such as metadata, data compression, or content negotiation.
  • Base64-encoded data URIs are 1/3 larger in size than their binary equivalent. (However, this overhead is reduced to 2-3% if the HTTP server compresses the response using gzip)
  • Data URIs make it more difficult for security software to filter content.
Community
  • 1
  • 1
Martin Buberl
  • 45,844
  • 25
  • 100
  • 144
  • 3
    CSS are re-downloaded on every request? That's a new one! Plus, if you have ever archived a file in your life, you would have noticed that the compression rate is not 2-3%! If I'm not mistaken, I've first seen this technique implemented on yahoo.com. ... clearly is not good practice! – StefanNch Jul 02 '13 at 08:30
  • @StefanNch that's not what it says. In the excerpt, "containing document" refers to the css file. – Christophe Sep 27 '13 at 01:17
9

I was using data-uri's for about a month, and Ive just stopped using them because they made my stylesheets absolutely enormous.

Data-uri's do work in IE6/7 (you just need to serve an mhtml file to those browsers).

The one benefit I got from using data-uri's was that my background images rendered as soon as the stylesheet was downloaded, as opposed to the gradual loading we see otherwise

It's nice that we have this technique available, but I won't be using it too much in the future. I do recommend trying it out though, just so you know for yourself

stephenmurdoch
  • 34,024
  • 29
  • 114
  • 189
3

I'd more inclined to use CSS Sprites to combine the images and save on requests. I've never tried the base64 technique but it apparently doesn't work in IE6 and IE7. Also means that if any images changes then you have to redeliver the whole lost, unless you have multiple CSS files, of course.

Steve Claridge
  • 10,650
  • 8
  • 33
  • 35
  • i already have sprites, i was wondering if i can optimize it even more with that method. – meo Mar 10 '11 at 10:09
2

I have no idea about general best practices but I for one would not like to see that kind of thing if I could help it. :)

Web browsers and servers have a whole load of caching stuff built in so I would have thought your best bet was to just get your server to tell the client to cache image files. Unless you are having loads of really small images on a page then I wouldn't have thought the overhead of multiple requests was that big a deal. Browsers generally will use the same connection to request lots of files so there are no new network connections being established so unless the volume of traffic through HTTP headers is significant compared to the size of the image files I wouldn't worry about multiple requests too much.

Are there reasons why you think there are too many requests going to the server at the moment?

Chris
  • 27,210
  • 6
  • 71
  • 92
  • 4
    cause number of requests is one of biggest perf hits if you care about perf its first thing to try and tackle. see yahoo's take http://developer.yahoo.com/performance/rules.html "Reducing the number of components in turn reduces the number of HTTP requests required to render the page. This is the key to faster pages." – MemeDeveloper Mar 07 '13 at 10:20
1

I would suggest it for tiny images that are used very often, for example common icons of a web application.

  • Tiny, because the Base64 encoding increases the size
  • Often used, because this justifies the longer initial load time

Of course support problems with older browsers have to be kept in mind. Also it might be a good idea to use the capability of a framework to automatically inline the images a data urls such as GWT's ClientBundle or at least use CSS classes instead of adding it to the element's style directly.

More information are gathered here: http://davidbcalhoun.com/2011/when-to-base64-encode-images-and-when-not-to/

Sebastian
  • 5,721
  • 3
  • 43
  • 69