How to make nice & scalable CSS buttons with JavaScript

Web programming topics
Post Reply
User avatar
Saman
Lieutenant Colonel
Lieutenant Colonel
Posts: 828
Joined: Fri Jul 31, 2009 10:32 pm
Location: Mount Lavinia

How to make nice & scalable CSS buttons with JavaScript

Post by Saman » 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.
demo.PNG
demo.PNG (18.78 KiB) Viewed 3555 times
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
In this article I will use PNG images for adding shades and corners to the buttons. PNG’s are great because you have 256 levels of alpha transparency compared to only 1 using GIF. Unfortunately, Internet Explorer 6 and down has a hard time understanding PNG transparency, especially as background images in CSS, except when using a number of filters and Microsoft-specific JavaScript queries. Even then, it doesn't do the job like modern browsers. Fortunately, IE7 supports PNG all the way, which means that we can already now start to integrate it in our web designs as long as things degrades nicely.

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
What we can't have: Full support in IE6. BUT, it will degrade nicely, so IE6 users will see the same buttons, but without the PNG image.

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> 
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:

Code: Select all

<a href="#" class="btn">Button</a> 
This should also work:

Code: Select all

<input type="Button" value="Submit this form" class="btn" /> 
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:

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>'));
       });
}); 
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:
shade.png
shade.png (1.26 KiB) Viewed 3556 times
btn2.png
btn2.png (1.02 KiB) Viewed 3556 times
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; } 
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:

Code: Select all

* html .btn span, * html .btn i { float: left; width: auto; background-image: none; cursor: pointer; } 
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):
grey.gif
grey.gif (1.33 KiB) Viewed 3556 times
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" /> 
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:

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; } 
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):
btns.png
btns.png (9.98 KiB) Viewed 3556 times
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; }         
Now this is how the buttons will look in IE6:
ie6.gif
ie6.gif (976 Bytes) Viewed 3556 times
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
btnex.zip
(4.13 KiB) Downloaded 392 times
Post Reply

Return to “Web programming”