Scalable CSS Buttons Using PNG and Background Colors

colorful buttonsThis guide will help you create your very own dynamic CSS buttons. We will accomplice this with the use of PNG files, transparency and background colors. This will allow the buttons to scale according to our needs and still be useable on older systems that do not support the fancy buttons.

You can find many CSS button scripts on the web. Many of them do not do what we like to accomplice in this guide. The following things are some of the flaws with other guides that we like do remedy in this guide

  • 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 images

We will use PNG images for adding shades and corners to the buttons. PNG’s has the benefit of having 256 levels of alpha transparency compared to only 1 using GIF. If you are still targeting  Internet Explorer 6 it would be wise to know that they do not support PNG at all. Fortunaly, IE7 supports PNG, which means that we integrate it in our web designs as long as things degrades nicely.

What we want for the buttons in this guide

  • 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 degrading for browsers without images or JavaScript

Here comes the code!

This code works quite well with our CSS code:

<a href="#"><i></i><span><span></span><i></i>Button</span></a>

But it is not pretty. This is what we want:

<a href="#" class="btn">Button</a>

But this could also work:

<input type="Button" value="Submit this form" class="btn" />

We can use JavaScript to convert the nice code into the ugly but useful version. Bellow is the code that does that and also some event handling for the button. The basic principle is that is will grab all anchors and input elements with the class “btn” and then convert them to anchors. They will degrade into a normal input button if JavaScript is turned of.

 var btn = { init : function() { if (!document.getElementById || !document.createElement || !document.appendChild) return false; as = btn.getElementsByClassName('btn(.*)'); for (i=0; i<as.length; i++) { if ( as[i].tagName == "INPUT" && ( as[i].type.toLowerCase() == "submit" || as[i].type.toLowerCase() == "button" ) ) { var tt = document.createTextNode(as[i].value); var a1 = document.createElement("a"); a1.className = as[i].className; a1.id = as[i].id; as[i] = as[i].parentNode.replaceChild(a1, as[i]); as[i] = a1; as[i].style.cursor = "pointer"; } else if (as[i].tagName == "A") { var tt = as[i].firstChild; } else { return false }; var i1 = document.createElement('i'); var i2 = document.createElement('i'); var s1 = document.createElement('span'); var s2 = document.createElement('span'); s1.appendChild(i1); s1.appendChild(s2); s1.appendChild(tt); as[i].appendChild(s1); as[i] = as[i].insertBefore(i2, s1); } // The following lines submits the form if the button id is "submit_btn" btn.addEvent(document.getElementById('submit_btn'),'click',function() { var form = btn.findForm(this); form.submit(); }); // The following lines resets the form if the button id is "reset_btn" btn.addEvent(document.getElementById('reset_btn'),'click',function() { var form = btn.findForm(this); form.reset(); }); }, findForm : function(f) { while(f.tagName != "FORM") { f = f.parentNode; } return f; }, addEvent : function(obj, type, fn) { if (obj.addEventListener) { obj.addEventListener(type, fn, false); } else if (obj.attachEvent) { obj["e"+type+fn] = fn; obj[type+fn] = function() { obj["e"+type+fn]( window.event ); } obj.attachEvent("on"+type, obj[type+fn]); } }, getElementsByClassName : function(className, tag, elm) { var testClass = new RegExp("(^|\s)" + className + "(\s|$)"); var tag = tag || "*"; var elm = elm || document; var elements = (tag == "*" && elm.all)? elm.all : elm.getElementsByTagName(tag); var returnElements = []; var current; var length = elements.length; for(var i=0; i<length; i++){ current = elements[i]; if(testClass.test(current.className)){ returnElements.push(current); } } return returnElements; } } 

Next step is to create some PNG images. We will use 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 needs to be quite big if you want the buttons to expand nicely without confusing graphics:

PNG shade image PNG button image

When this is all done and done, we need create the CSS. The first problem to solve is to make the CSS place the four corner of the image on the right spot, without overlapping. So here are the general CSS rules to add:

  1. .btn { line-height: 1.25; display: block; position: relative; background: grey; padding: 5px; float: left; color: #fff; text-decoration: none; cursor: pointer; }
  2. .btn * { font-style: normal; background-image: url(btn2.png); background-repeat: no-repeat; display: block; position: relative; }
  3. .btn i { background-position: top left; position: absolute; margin-bottom: -5px; top: 0; left: 0; width: 5px; height: 5px; }
  4. .btn span { background-position: bottom left; left: -5px; padding: 0 0 5px 10px; margin-bottom: -5px; }
  5. .btn span i { background-position: bottom right; margin-bottom: 0; position: absolute; left: 100%; width: 10px; height: 100%; top: 0; }
  6. .btn span span { background-position: top right; position: absolute; right: -10px; margin-left: 10px; top: -5px; height: 0; }

We included a default background-color: grey 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.

Basically, we can now start using our code. But if you also like to target Internet Explorer 6 then you need to also add the following rules to address IE6.

  1. * 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 button

It is time to create some buttons. Try this code:

  1. <a href="#" class="btn blue">This is a blue button</a>
  2. <a href="#" class="btn green">This should be a green button</a>
  3. <input type="Button" value="Submit this form" class="btn pink" />

the class names are what we are going to use in the CSS file to customize our buttons. Let’s also add some hover and active colors:

  1. .btn.blue { background: #2ae; }
  2. .btn.green { background: #9d4; }
  3. .btn.pink { background: #e1a; }
  4. .btn:hover { background-color: #a00; }
  5. .btn:active { background-color: #444; }
  6. .btn[class] { background-image: url(shade.png); background-position: bottom; }

We use the [class] selector to prevent IE6 from reading the PNG File. This code should look like this in newer browsers:

colorful buttons

You can now easily create your own PNG images and classes to create CSS buttons that will suit your design.

If you like then you cane somewhat compensate to IE6 by adding borders to the button classes. Use the star HTML hack again to touch up the buttons for IE6:

  1. * html .btn { border: 3px double #aaa; }
  2. * html .btn.blue { border-color: #2ae; }
  3. * html .btn.green { border-color: #9d4; }
  4. * html .btn.pink { border-color: #e1a; }
  5. * html .btn:hover { border-color: #a00; }

Now this is how the buttons will look in IE6:

Buttons in IE6

I hope you have enjoyed this guide and that you find it useful. Feel free to use the buttons in your own project if they suit your needs and requirements. Have fun and happy coding! Also check out buttons in HTML5 for some great result!

Gallery | Galleria | Avant Garde