How to make nice & scalable CSS buttons with JavaScript
Posted: Sat Mar 06, 2010 2:34 pm
This article is about something that has not yet been covered in the latest button-trend: Dynamic CSS Buttons using PNG, transparency and background colours that degrades nicely and supports full scalability. With full scalability I mean it should resize in all directions according to the font size and content.
There are many CSS button scripts out there, but neither of them does it for me. Here are some of the flaws I found:
What we want
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:
That doesn't look pretty. But if you don't mind using HTML code like that, you won't need the JavaScript explained further down for anchors. Personally, I would prefer something like this:
This should also work:
The JavaScript
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:
The Graphics
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:
I included a default background-color: #aaa in the .btn definition. This is the color it will have if no other style is set further down the cascade. If you have altered your general line-height previously in the CSS you might have to correct it in the .btn rule for IE7. Also, please note the second line rule background-image: url(btn2.png). This is where your custom-made button image goes.
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:
That takes care of Explorer shrinkwrap bug (and other small rendering issues) and at the same time sets the background image to none This is how it should look now (in modern browsers):
What's Next?
Now we are ready to go. Let's try this code here:
Looking good! Do you see the class names I added? That's what we are going to use in the CSS file to customize our buttons. Let's also add some hover and active colors:
The last row contains the shaded image I used as background for the images. Naturally, you can have several backgrounds for different button classes. I used the [class] selector to prevent IE6 from reading the PNG file. This code should render something like this in modern browsers (note the shade and vague lines compared to the previous example):
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):
Now this is how the buttons will look in IE6:
I know that IE6 is still the by far most popular browser, but it belongs to the past. IE7 is taking big steps forward and I'm sure that within 1-2 years, the majority of IE users will be using version 7. This still works for IE6 and doesn't look bad and that's good enough for me.
Enjoy your new buttons!
Example Code
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