In solving some of the problems needed to create my pure CSS progress bars with rounded corners, I ended up using a combination of two backgrounds: a background-color and a background-image. Unfortunately, images are rather static, inflexible things. They require you to make a new image every time you want to use a slightly different colour… or do they?
While playing with different colours in my design (I like to prototype in code), the inability to change the colour of the image on the fly didn’t sit well with me. After all, it’s just a bunch of bytes being parsed by the browser before being rendered on the screen. If we can provide that data in CSS as a data-uri, as I already showed in my previous article, then surely we can have some level of control over what that data represents. I got a bit obsessed about this and over the weekend I managed to get this insanity to work. By dynamically generating a data-uri, we can have a 1-pixel image of any colour we want.
The result is available on Github. Check out the demo to see it in action.
Dynamic CSS
The one thing this solution requires is some level of dynamic control over the styles that define the image. For all I care, this can be SASS, a perl script that generates static CSS on the server or even PHP. I used LESS for this, because I was already using it anyway and it allows me to write JavaScript in my stylesheets. You can easily stick with with whatever you are already using and use LESS on the side, but the ideas in this technique are not tied to LESS in any way; it shouldn’t be hard to port to other tools.
A Dynamic Image
For a solid, single-colour background, all you need is a single pixel image. In the previous article I used this one:
It’s the smallest possible (43 bytes) 1-pixel image that is valid and visible on the web. This one happens to be red, but as I will show it can be any colour. I chose GIF because it was smaller than PNG for my purposes, but it’s probably possible to generate a PNG as well. GIF is also a very old and well understood file format, and before you ask: it’s no longer trapped in intellectual property limbo.
The goal here is to take a colour (say, red) and generate a 1 pixel gif from that. To be able to do that, we need to understand the GIF file format a little bit. Fortunately Wikipedia does a pretty good job a that, so I am not going in too much detail. What is important is that in GIF, the image is split into two parts: the palette is stored as a global colour table, separate from the image data. This means, that in order to change the colour of a one pixel image, all we need to do is change that colour in the palette; there’s no need to touch anything else.
The simplest possible GIF for this has only 43 bytes: it has just one pixel and a 1-bit palette (two colours, of which only one is used).
If we want to have a 1-pixel GIF of another colour, all we need to do is find colour #0 in the palette. Let’s do this for red_pixel.gif:
00: 4749 4638 3961 GIF89a 06: 0100 0100 f000 ...... 0c: 00ff 0000 ffff ...... 12: ff21 f904 0000 .!.... 18: 0000 002c 0000 ...,.. 1e: 0000 0100 0100 ...... 24: 0002 0244 0100 ...D.. 2a: 3b ;
As expected, the first colour in the palette has a hexadecimal value of #FF0000, or 255,0,0 RGB. Changing this to #00FF00 will make it green and #0000FF blue. Just load up the file in a HEX editor of choice (Hex Fiend is nice) and try it.
Now, being able to change an image colour by changing some values in a HEX editor is nice, but it’s hardly flexible. To make this useful for anything, we need to be able to change the GIF from CSS. Yay for data URIs!
Data URIs allow content to be embedded in CSS, where it can be used for backgrounds etc. As we are generating CSS using LESS, all we need is a way to generate a data URI for the desired image!
The data URI for red_pixel.gif looks like this:
data:image/gif;base64,R0lGODlhAQABAPAAAP8AAP///yH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==
The 43 bytes have been turned into 61 ASCII characters using Base64 encoding, plus some stuff describing this is a data URI with an encoded GIF. If we want to change the GIF, all we need to do is change the data URI and we’re golden.
Now, it would be possible to just generate a whole GIF from an RGB bitmap and Base64 encode that, but that would be a lot of work. We really only need to change the 3 bytes representing the primary colour in the palette. The rest of the image is left untouched, so just swapping those three bytes out in the data URI is enough to get a 1-pixel GIF in a different colour.
Unfortunately, the way Base64 works makes this a bit harder. Base64, as the name suggest, encodes data in 64 bit chunks. Every 6 bits are represented by 1 ASCII character. With our luck, the first four bits of the primary RGB pair get encoded in one such 6-bit chunk and the last two in a separate 6-bit chunk. This means replacing the 6 bits in the palette, requires re-encoding the 12 surrounding bits into 5 characters.
Caring not too much about efficiency, this can be done in a few lines of JavaScript (try in jsFiddle):
Generating a GIF with the desired primary colour now becomes a simple matter of inserting these 5 characters in the right place in the Data URI:
"data:image/gif;base64,R0lGODlhAQABAPAAA" + encodeRGB(0,0,255) + "///yH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==)"
Doing this in LESS is a bit complicated, as Less is very picky about syntax, but it’s easy to just cram all of that ugly code into a mixin, so that when it is used, you can just forget about all of that:
This gives div.progress item a gif with the desired colour as a background. The trick only works in browsers that support data-URIs, so IE7 and below get no love.
As a bonus, I also liked to be able to specify the colour as a HEX value. Try that out in a jsFiddle here. The whole thing is available as a LESS module on Github. It really works, check the demo!
I would love to see someone do a PNG version of this hack. I didn’t need it myself, but a 24 bit PNG would allow specifing an Alpha (opacity) value as well!
Hi. I’ve implemented PNG generator with LESS. Here is code and underlines demo.
Great blog! Is your theme custom made or did you download it from somewhere?
A theme like yours with a few simple adjustements would really make my blog
stand out. Please let me know where you got your design. Kudos
Hello, after reading this awesome article i am also
cheerful to share my knowledge here with colleagues.
Unquestionably consider that which you stated.
Your favourite reason seemed to be at the web the esiest thing tto be minndful of.
I say to you, I definitely get annoyed while people think about issues tha they just don’t recognise about.
You controlled to hit the nail upon the highest and outlined out
the entire thing without having side-effects , other folks can tke a
signal. Will probably be again to get more.
Thanks
Alsoo visit my weblog; first aid kit
Remarkable things here. I am very glad to peer your article.
Thank you a lot and I am taking a look ahead to contact you.
Will you kindly drop me a mail?
Nice! I used your code to get around an SVG blending limitation in Firefox. http://stackoverflow.com/questions/13669491/are-there-ways-to-use-additive-color-mixing-in-web-development/25321661#25321661
you are actually a excellent webmaster. The site loading pace is amazing.
It seems that you are doing any unique trick. In addition, The contents are masterwork.
you’ve performed a excellent task in this topic!