Okay; very late on Sunday, I posted about a curved borders hack to end all (or most) curved border hacks. I was a bit bushed after all the work, so was too tired to explain the hack.
First, a short description of it, for all you people that didn’t read the post:
border:2px solid #333;
The above would render such as this:
This will work in practically every browser. Don’t believe me? Here’s the test page, and here’s the CSS for that page.
As for native ability – as far as I know, there is only one single browser that can do curved borders.
That browser is, of course, Firefox; the greatest browser in the world.
Unfortunately, not even that great god of a browser gets it all right:
In the example image (which is rendered using Firefox’s native rendering engine – try for your self (Mozilla browsers only)), you can see that the background image is leaking.
I’m currently compiling a build of Mozilla to see if I can get working on a fix for that (unlikely, as my C++ is woeful, but I will try…).
Anyway – look in the example with your own browser and you will see that your own browser can now display it properly.
So, how was it done?
It was a three-step process:
- get the css and parse it.
- for each element which has a border-radius, remove the border from the element, correcting the size of the element by adding the missing border widths to the elements, and giving the element a custom background image which fakes the border.
- create the image
It’s surprising (and there’s probably a universal law that explains it), but the shorter a problem’s description, the more difficult it usually is. Of the three items above, the easiest was the second.
Grabbing the CSS
I spent a week researching how to grab CSS straight from the source before the browser parses it. I gave up after a good read through the W3C’s DOM specs turned up nothing.
Suddenly, the answer was clear: XMLHttpRequest! Why not just grab the actual source, instead of trying to access it through some non-existant DOM interface.
Actually, once I thought of the solution, it was pretty simple… it’s just that I spent so long trying to figure it out that I was damned frustrated.
Parsing the CSS and fixing the elements
Nyeh – read the source and figure it out for yourself 🙂 It’s pretty self-explanatory.
Dean Edwards, as usually, was a life saver. His
cssQuery code made it a cinch to grab arrays of each affected element.
The background image
I’m not really a graphical coder, so writing the background painter involved a bit of thought for me.
Basically, the solution, though, was pretty simple again, after I’d worked it out.
You need to paint two images – the first one is a mask, and the second is the border. The mask is for figuring out what should be transparent and what should not.
First, you build the mask. This involves painting a rectangle in a certain colour (eg; black), and then painting the border in another color (white). If the element is supposed to have a background image or colour, then you need to fill in the space between the borders.
Then, you paint the real image. This involves first painting a rectangle in the element’s background colour (if specified), then tiling the background (again if specified).
Once the two images are done, you just go through the mask, a pixel at a time, and whenever a “transparent” indicator (black, in this example) is found, the corresponding pixel in the real image is painted “clear”.
There are improvements that could be made – the script has not been tested with multiple colours, and I haven’t coded any border styles (dashed, dotted, etc) into it.
If there is interest in the script, then I may improve on it.