In this article I will show how to combine the advantages of JPG's high compression rate with the flexibility of having alpha channels like we use them in PNG. Open the demo to see this technique in action, a semi transparent JPG in front of HTML text:
Demo of JPG with alpha channel.As all modern browsers support images with alpha channels1 it has become fairly easy for designers to place semi transparent images in front of irregular backgrounds.
The weapon of choice will be PNG as it is the only widespread image format that supports alpha channels (WEBP is a promising alternative, but currently only supported in Chrome and Android)[Update As Mathias Bynens correctly pointed out in the comments: Opera supports WebP too].
But PNG has its drawbacks. It comes in 2 flavours: a lossless compressed image with 24bit true colors. Images in this format look superb, but can quickly grow HUGE.
And then there's the 8bit (256 color) PNG with alpha channel. When exported cleverly with the right color palette and the right amount of dithering it can be rather small, but most of the time a loss in image quality because of the limited color palette is unavoidable. Look closely at the color gradients in this example:
8bit PNG.Wouldn't it be great if we could get the high compression and rich color depth of the JPG image format together with alpha channels? Actually, with the help of SVG, this is a breeze.
Open demo of JPG with alpha channel.This demo contains a JPEG that is wrapped into an SVG. The alpha channel then is created via the SVG "mask" element. The SVG and the JPG (compressed at 50%) combined weigh in at 26kb. The same motive exported into a 8bit PNG will be 32kb. Exported into a 32bit PNG it will be whopping 120kb.
Creating the SVG wrapped alpha JPG:
1. Preparing the JPG
Here's how to prepare the JPG:
2. Creating the SVG:
Fire up your editor and create a new SVG. We will put the JPG into a symbol element, so we need only 1 reference to the JPG that we then can use across our document:
<symbol id="img_corona"> <image width="840" height="400" xlink:href="corona.jpg" /> </symbol>
We define a mask. As we only want to have the "alpha part" of our image placed exactly above the "image part",the JPG must be positioned 50% to the left:
<mask id="mask_corona"> <use xlink:href="#img_corona" width="840" height="400" x="-420" y="0" style="overflow:hidden;"/> </mask>
Almost there. Let's put a reference to the symbol containing the image inline. And now we will cut off the right part of the image that contains the "alpha-channel":
<use id="corona" xlink:href="#img_corona" width="430" height="400" style="overflow:hidden;"/>
Last thing to do: apply our "alpha channel" to the image with CSS. Here's the code in one piece: <svg version="1.1"; preserveAspectRatio="none"; xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink"> <style type="text/css"> <![CDATA[ #corona{ mask :url(#mask_corona); } ]]> </style> <symbol id="img_corona"> <image width="840" height="400" xlink:href="corona.jpg" /> </symbol> <mask id="mask_corona"> <use xlink:href="#img_corona" width="840" height="400" x="-420" y="0" style="overflow:hidden;"/> </mask> <use id="corona" xlink:href="#img_corona" width="420" height="400" style="overflow:hidden;"/> </svg>
I hope I showed that this is can be an elegant method to get highly compressed images with alpha channels. This method can be used in every browser that supports SVG which means browser support is pretty good.
If you want to check out this example you can play with this pen or check out my github repo with my SVG experiments.