There are many CSS button scripts out there, but neither of them does it for me. Here are some of the flaws I found:
- They won't scale vertically
- The HTML source is ugly and full of meaningless tags
- You need several images for corners and borders
- You can't add a hover effect without major code-breaking
- You need several images for different background colours
What we want
- Full scalability in all directions
- The use of one single png image for the button without overlapping
- The possibility to change background colors behind the image (also on hover)
- Super-clean HTML markup
- Unobtrusive JavaScript for altering the DOM
- Pure CSS for styling
- Possibility to style anchors as well as form buttons
- Full degradability for browsers without images or JavaScript
The HTML
Serving up a semantically meaningless HTML for this task wasn't easy. But I did find a solution that works quite well with our CSS code:
Code: Select all
<a href="#"><i></i><span><span></span><i></i>Button</span></a>
Code: Select all
<a href="#" class="btn">Button</a>
Code: Select all
<input type="Button" value="Submit this form" class="btn" />
Let's add some unobtrusive JavaScript magic to convert that for us. This script I composed is rather lengthy (60 rows) since I needed to include some functions for event handling and such. But the basic principle is that it will grab all anchors and input elements with the class “btn” and then convert them to anchors (if they are input elements) and finally add the empty calories. The good thing about replacing input elements with JavaScript is that they still behave like input elements (hitting return will submit the form, etc). Besides that, they will also degrade to a normal input button if JavaScript is turned off.
Anyone who is already using jQuery framework can try this light-weight script instead:
Code: Select all
$(document).ready(function(){
$('.btn').each(function(){
var b = $(this);
var tt = b.text() || b.val();
if ($(':submit,:button',this)) {
b = $('<a>').insertAfter(this). addClass(this.className).attr('id',this.id);
$(this).remove();
}
b.text('').css({cursor:'pointer'}). prepend('<i></i>').append($('<span>').text(tt).append('<i></i><span></span>'));
});
});
Next step is to create some PNG images. I used two images for this purpose, one general with a subtle gradient and diagonal lines for the background, and then a large button with contours and white corners for the main button. It need to be quite big if you want the buttons to expand nicely without confusing graphics:
The CSS
When this is all done and done, we need to get the CSS going. The big challenge here was to make the css place the four corner of the image on the right spot, without overlapping. Why no overlap? Well, if you have a PNG image filled with 50% black and let it slide on top of itself using sliding doors or some other technique, it will have overlapping areas with 75% black. Not good. So here are the general CSS rules to add:
Code: Select all
.btn { display: block; position: relative; background: #aaa; padding: 5px; float: left; color: #fff; text-decoration: none; cursor: pointer; }
.btn * { font-style: normal; background-image: url(btn2.png); background-repeat: no-repeat; display: block; position: relative; }
.btn i { background-position: top left; position: absolute; margin-bottom: -5px; top: 0; left: 0; width: 5px; height: 5px; }
.btn span { background-position: bottom left; left: -5px; padding: 0 0 5px 10px; margin-bottom: -5px; }
.btn span i { background-position: bottom right; margin-bottom: 0; position: absolute; left: 100%; width: 10px; height: 100%; top: 0; }
.btn span span { background-position: top right; position: absolute; right: -10px; margin-left: 10px; top: -5px; height: 0; }
Basically, we can now start using our code. But first we need to tame Internet Explorer 6 by adding the following rules in your preferred environment. I've added a star html hack to address IE6 only here in the example, but you might as well use conditional comments:
Code: Select all
* html .btn span, * html .btn i { float: left; width: auto; background-image: none; cursor: pointer; }
What's Next?
Now we are ready to go. Let's try this code here:
Code: Select all
<a href="#" class="btn blue">This is a blue button</a>
<a href="#" class="btn green">This should be a green button</a>
<input type="Button" value="Submit this form" class="btn pink" />
Code: Select all
.btn.blue { background: #2ae; }
.btn.green { background: #9d4; }
.btn.pink { background: #e1a; }
.btn:hover { background-color: #a00; }
.btn:active { background-color: #444; }
.btn[class] { background-image: url(shade.png); background-position: bottom; }
You can now easily create your own PNG images and classes to create CSS buttons that will suit your designs.
To somewhat compensate to IE6, we can add borders to the button classes. I used the star HTML hack again to touch up the buttons for IE6 like this (thanks T3rmin8):
Code: Select all
* html .btn { border: 3px double #aaa; }
* html .btn.blue { border-color: #2ae; }
* html .btn.green { border-color: #9d4; }
* html .btn.pink { border-color: #e1a; }
* html .btn:hover { border-color: #a00; }
Enjoy your new buttons!
Example Code