The goal of this tutorial is to explain how to set up Jawr to generate base64 encoded images in the CSS bundles.
As you know, one of the main rules to increase performance in your web application is to reduce the number of HTTP requests.
One of the way to achieve this is to create image sprites, which combines multiple images in a single image. Jawr already provides a way to handle this case. Please take a look at the Jawr sprite documentation
So, with sprite all the reference of the images defined in your CSS will point to one or a few sprites, which will reduce the number of HTTP requests.
There is another way to reduce the number of HTTP requests by encoding the content of the images in base64.
It means that in you generated bundle, the URL references to the image will be replaced by the content of your images.
So your images will be embedded in your CSS. This will increase the size of your CSS files, but will reduce drastically the number of HTTP requests, as there will be no HTTP request required for your images.
Here is an example of the base64 encoding of a CSS image reference:
background-image:url("../../images/logo.png");
Will be transformed like this :
background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA...AAElFTkSuQmCC");
So here, the content of the image is set directly in the CSS file.
If we take a look at the generated content, we have:
The base64 encoded resources is handled by all major browser except for IE6 and IE7, but fortunately there is a workaround for this, which is the use of MHTML references.
MHTML stands for MIME HTML. It’s a file format which allows you to combine multiple contents like images in one file.
So for these browsers, instead of using the data URI, we will use MHTML references. Here is an example of MHTML use in a CSS file :
/* Content-Type: multipart/related; boundary="_ANY_SEPARATOR" --_ANY_SEPARATOR Content-Type:image/png Content-Location:logo Content-Transfer-Encoding:base64 iVBORw0KGgoAAAANSUhEUgAAA...AAElFTkSuQmCC */ #logo { background-image: url(mhtml:http://www.mycomp.com/css/home.css!logo); }
Here we can see that the MHTML part is set at the top of the file in a commented section.
In the first line, we define the boundary used to separate the declaration of each resource.
Then for each resource, we have some information: - Content-Type : the content type - Content-Transfer-Encoding : the encoding used for this resource - Content-Location : the property which will allow us to reference this particular resource in the CSS file
If we take a look at the image URL, we have:
As we are using absolute URL, Jawr will generate a bundle version for HTTP requests and another one for HTTPS ones. Otherwise IE will raise an warning saying that you have SSL and non SSL content in your page.
As we’ve seen, we must use absolute URL to reference the current CSS which contains the MHTML content. As you know, Jawr generates the bundle at server startup or at build time.
At this stage, Jawr doesn’t know the application absolute URL. So Jawr will use a placeholder named JAWR_BUNDLE_PATH in the generated bundle.
The resolution of the absolute path will be done at runtime for the first request, then it will be put in cache.
When you generate the Jawr bundles at build time, if you have defined absolute paths for the following properties :
- jawr.url.contextpath.override : The context path of the application for HTTP - jawr.url.contextpath.ssl.override : The context path of the application for HTTPS
The values of these properties will be used to reference the absolute path of the CSS bundles.
Otherwise Jawr will set the reference to the CSS bundles and will let a place holder for the web application URL.
#logo { background-image: url(mhtml:http://{WEBAPP_URL}/gzip_a08d115cf05a5ef92f289b0a7510057f.ie6@/css/home.css!logo); }
You will have to process the content of these bundles to replace WEBAPP_URL by the right web application URL.
Please check the “quickstart” tutorial for the instruction about Jawr installation in your project.
Since version 3.3, Jawr is able to generate variant bundles from postprocessors. This means that by just setting the correct postprocessor in your bundle, Jawr will generate the content of the CSS for the different browsers.
The id of the postprocessor to use is base64ImageEncoder.\ There are 3 properties related to the base64 encoding available in the Jawr configuration :
Property name | Type | Purpose | Default value |
---|---|---|---|
jawr.css.postprocessor.base64ImageEncoder.encode.by.default | Boolean | Enable/disable the base64 image encoding by default | true |
jawr.css.postprocessor.base64ImageEncoder.maxFileLength | Integer [ The maximum size (in bytes) of the image to encode in base64 | 30000 | |
jawr.css.postprocessor.base64ImageEncoder.encode.sprite | Boolean | Enable/disable the base64 image encode on generated sprite image | False |
The property jawr.css.postprocessor.base64ImageEncoder.encode.by.default will define if the postprocessor should encode the CSS image in base64 by default or not. If the jawr.css.postprocessor.base64ImageEncoder.encode.by.default is set to true, by default all the CSS images will be encoded, except if the are followed by the annotation : jawr:base64-skip
.style1 { background: url('../img/img1.png') ; height : 20px; } .style2 { background: url('../img/img2.png') ; /** jawr:base64-skip */ height : 20px; }
In this example, if jawr.css.postprocessor.base64ImageEncoder.encode.by.default is set to true, only the first image URL will be encoded, the second one will be skipped.
If the jawr.css.postprocessor.base64ImageEncoder.encode.by.default is set to false, by default all the CSS images will be encoded, except if the are followed by the annotation : jawr:base64
.style1 { background: url('../img/img1.png') ; height : 20px; } .style2 { background: url('../img/img2.png') ; /** jawr:base64 */ height : 20px; }
In this example, if jawr.css.postprocessor.base64ImageEncoder.encode.by.default is set to false, only the second image URL will be encoded, the first one will be skipped.
In our example, we will define our bundle like this :
jawr.css.bundle.base64Bundle.id=/css/base64Bundle.css jawr.css.bundle.base64Bundle.mappings=/css/one.css jawr.css.bundle.base64Bundle.bundlepostprocessors=cssminify,base64ImageEncoder jawr.css.bundle.base64Bundle.filepostprocessors=base64ImageEncoder
Warning:
You should noticed that we have set the CSS minifier before our base64ImageEncoder. We use this configuration because the CSS minifier would have removed the MHTML part which in comment.
It is also important to set the base64ImageEncoder not only as a bundle post processor but as a file post processor AND a bundle post processor, because this post processor needs to prepend the MHTML part to the bundle and also to rewrite the URL for each file.
So never use this post processor only as a bundle post processor or only as a file post processor.
To use the base64ImageEncoder with composite bundle, you need to define the base64ImageEncoder as file postprocessor for the child bundles, and as bundle postprocessor for the composite bundle.
jawr.css.bundle.base64CompositeBundle.id=/css/compositeBundle.css jawr.css.bundle.base64CompositeBundle.composite=true jawr.css.bundle.base64CompositeBundle.child.names=childOne,childTwo jawr.css.bundle.base64CompositeBundle.filepostprocessors=none jawr.css.bundle.base64CompositeBundle.bundlepostprocessors=cssminify,base64ImageEncoder jawr.css.bundle.childOne.mappings=/css/one.css jawr.css.bundle.childOne.filepostprocessors=base64ImageEncoder jawr.css.bundle.childOne.bundlepostprocessors=none jawr.css.bundle.childTwo.mappings=/css/dir/two.css jawr.css.bundle.childTwo.filepostprocessors=base64ImageEncoder jawr.css.bundle.childTwo.bundlepostprocessors=none
Create an /img directory at the root of your web application and copy 2 png images in it and rename them to img1.png and img2.png .
Write a test CSS file named /css/one.css and add the following content:
.style1 { background: url('../img/img1.png') ; height : 20px; } .style2 { background: url('../img/img2.png') ; /** jawr:base64-skip */ height : 20px; }
Here you should noticed that we have added an annotation to image reference of /img/img2.png : /** jawr:base64-skip */. This annotation tells to the base64ImageEncoder to not encode this image in the process but rewrites the URL so it goes through the Jawr image servlet.
Write a test JSP page and add the following content:
<%@ taglib uri="http://jawr.net/tags" prefix="jawr" %> <%@ page contentType="text/html;charset=UTF-8" %> <html> <head> <jawr:style src="/css/base64Bundle.css" /> </head> <body> <div class="style1"></div> <div class="style2"></div> </body> </html>
Deploy your application to a server. Open the JSP you created with a firefox browser. If you take a look to the content of the CSS bundle, you should find the data URI reference of your image. You can also check with Firebug that there is no extra HTTP request made for your image.
Then open the JSP you created with an IE6 or IE7 browser. If you take a look to the content of the CSS bundle, you should find the MHTML part at the top of your bundle.