For quite some time at Josh Software, we have been concentrating on improving backend server performance. You can read about load testing and bench-marking and improving upload performance using nginx upload module. This post is about improving frontend performance by getting your pages to load faster using techniques like sprites, data-uri and jammit.
These tools have been around for about a year now — and are highly recommended. First off – basics:
Data-uri
Data-uri provide a way to send binary data in-line in the CSS. So you can embed images (not links) directly into your HTML, CSS or even JS! For example:
.bullets { margin-left: 20px; background: url('data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/ //+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U g9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC') top left no-repeat; }
However, there are few disadvantages of data-uri, some of them critical enough to consider its usage!
- Data-uri is limited to 32kb
- Internet Explorer 7 and below do not support data-uri. (You would be surprised how many people still use IE7 and even IE6!)
Sprite
Sprites have been used since the 70’s but its a recent entrant for combining with CSS. Sprites have been heavily used in gaming and 3-D hardware graphics. A sprite is a bunch of images grouped together into a single image. A CSS Sprite uses the image offset to render inner images. A good example of sprite code is here.
In the CSS, we use the background-position relative to the sprite image! If a website which has 50 tiny images, 50+ requests are sent to the server just to render that page. Using sprites, it would be only 1 request for a single image. The remaining images are rendered as offsets of the sprite. This reduces my server load from 50 to 1 for the images! Considering network latency, HTTP headers processing etc. — this itself brings on a solid performance boost!
There are plenty of ways to generate a Sprite . There are a few good resources for generating sprites — there is also a topic floating on quora on this (my inspiration for the blog btw). I preferred to write my own quick sprite generator. The gist is available here.
Using it is simple.
# this creates a png, so don't add the extension css = SpriteWriter.new("/path/to/images/folder", "/path/to/sprite/img", "/path/to/css") css.generate
Some examples of the work we have used sprite is at List.ly. If you look at the details of this page, you would find a tp-sprite.png The corresponding CSS shows how it is used.
Jammit
Jammit is a top-grade asset packaging library. It provides excellent compression techniques. It is highly configurable and can be used in different pages in different ways. It can be used along with data-uri, so it provides state of the art techniques for caching and serving images, CSS and JS.
It is frequently said that data-uri have now replaced using sprites. However, I dis-agree! Browsers which do not support datauri should also be catered to.
Using Jammit now provides us one alternative:
“embed_assets datauri” can be turned on in jammit. This turns on data-uri support for only those browsers which support data-uri. Others will ‘automagically’ be served the unmodified stylesheets!
In this way, we can choose which technique we require to load pages faster.
However, Jammit does not support sprites & datauri together. In my next post, I plan to show how we modified jammit code to serve sprites or datauri depending on the browser!
So, we now crank out the best possible options to load pages faster for ANY browser – be it datauri or sprites!
Stay tuned for further updates here.
I hope you found this article valuable. Feel free to ask questions and give feedback in the comments section of this post. Thanks!
A sprite is not a group of images grouped together into a single image, see http://en.wikipedia.org/wiki/Sprite_%28computer_graphics%29
Sprite being “a graphical overlay” would be more accurate.
However, I guess, the aim of this post is not the get into the internal details of a sprite but how it can be used.
I think the miscommunication is in the specific use of the word sprite. A sprite is (one of many definitions) one of the many single images from the larger resource. An image containing many smaller images to be rendered individually is a sprite sheet.
Oh come on, this has to be one of the most ridiculous comments ever!
Nice post, I like the Sprite Generator. You should also take a look at my asset_id library http://github.com/moocode/asset_id to help page loading speeds. I haven’t tried it with jammit but it works with asset_packager so it should work.
I liked asset_id – pretty good idea! You could use the gist and add sprite generation too — would be a win-win 😉
Please post more fried chicken stories!!1
check this out for a cross-browser solution for the data-uri:
http://www.phpied.com/the-proper-mhtml-syntax/
in a nutshell, you can provide mhtml data uri for ie and regular for all other browsers
+1 Awesome post.
I bow down humbly in the presence of such gratenses.
Data-uri is limited to 32kb
Afaik, this is only the case in IE8 and IE9. This limit is not present in other browsers
Yes Ruudjah, you are right. This is a Internet Explorer statistic. However, most compression engines tend to not convert larger images into data-uri due to pending incompatibility.
This seems like a way to inject nefarious JavaScript into a page beneath the radar of content scanners.
I think it is irresponsible of you to be promoting this.
Hi Steven,
I guess you have mis-understood. Datauri and sprites are accepted techniques to increase page-loading performance. Jammit is a compression asset manager among other things.
Content scanners will scan ALL rendered HTML — so if someone inserts malicious JS, it will definitely be scanned!
Like vzmind has mentioned, I too am keen to see why is nasty. Please give more details.
This is like saying you can do nefarious things with JavaScript, therefore the promotion of JavaScript is irresponsible.
Damned Steven, that s frightning. Could you elaborate? Do you speak about a possible nasty use of data uri?
Hi Gautam,
Just wondering did you create the codes for list.ly ?
If not, could you recommend anyone?
Avin
Hi Avin,
Yes, we have built list.ly Do send an email at info@joshsoftware.com or if you have a requirement just update your details at:
http://www.joshsoftware.com/ContactUs
hey Gautam. Interesting article.
Did you actually do some performance testing with data uris? Because in a test I just did, my page load time actually increased – due to a larger css file. Even though my requests (for css images) have gone done.
What’s your experience?
We have used datauri in list.ly and performance is good. We dont have any benchmarks for this. If you are using same image multiple time in css then css file size increase so better use separate css class for each image or use sprite image. Also dataurl is base64 encoded data so data size increase after encoding. For this you can use gzip compression in your server to reduce css response size.
I see. Thank’s alot for you answer. Gonna try this out and performance test it the next release.
Very good written story. It will be useful to anybody who employess it, as well as yours truly :). Keep up the good work – can’r wait to read more posts.