Process through Super Buttons – A CSS methodology
Posted Aug 30, 2011 by Dustin Weatherford
Today we’re going to explore a fancy button in HTML and CSS. Save to note that the main focus of this article is not to explore how to build buttons in CSS and HTML. Everyone does that already. Instead, we will touch base on fundamental design patterns in HTML and CSS through class driven development technique. Let’s start with some HTML:
[geshi lang="css"]
< a href=”#” class=”button” >
< span > Youre Welcome! < /span >
< /a >
[/geshi]
So simple! It’s important that we always define our HTML with as few tags as possible and one may say that the span tag in this structure is a bit overkill. Less HTML keeps code clean and readable for other developers but when it comes to defining page elements that are design heavy, it is better to have more control. In the case of buttons, a child span is usually a good idea.
What I like to do when defining my CSS is to start with the innermost element and work my way out. This strategy greatly reduces the number of surprise adjustments to parent elements. We’ll touch base more on this later. Let’s style our button:
[geshi lang="css"]
.button span {
display: block;
padding: 3px 15px;
border: 1px solid #b2e097;
border-radius: 6px;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
background-color: #91d26c;
background: -webkit-gradient(linear, left top, left bottom, from(#91d36d), to(#45ae29));
background: -moz-linear-gradient(top, #91d36d, #45ae29);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=’#91d36d’, endColorstr=’#45ae29′);
font: bold 20px ‘Helvetica’, verdana, sans-serif;
color: #fff;
text-shadow: 0px 1px 2px #888;
}
[/geshi]
Now our span looks actionable. Since most of the button’s look and feel is defined on the span, the only real reason for the parent anchor is to allow for click-ability, javascript targeting, and a subtle double border. Let’s add that border now:
[geshi lang="css"]
.button {
display: inline-block;
border: 1px solid #91ba6c;
border-radius: 6px;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
text-decoration: none;
}
[/geshi]
We add the same border radius as the child and a darker border to make it pop. Note the use of the display property on both elements. The inner span receives display: block; allowing it to control the inline height of the parent anchor. If the span was to remain an inline element, its padding would have no control over its parent height. The anchor is set to display: inline-block; for two reasons; inline allows for inline alignment property inheritance from the parent, and block so that it will keep the width of our button only as wide as its contents. Now, let’s add our button pseudo classes:
[geshi lang="css"]
.button:hover span {
background-color: #91d26c;
background: -webkit-gradient(linear, left top, left bottom, from(#45ae29), to(#91d36d));
background: -moz-linear-gradient(top, #45ae29, #91d36d);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=’#45ae29′, endColorstr=’#91d36d’);
}
.button:active span {
background: #91d26c;
}
[/geshi]
By focusing our design on the children of the anchor we have much more class control over our button. Let’s utilize some class chaining to make more button states.
[geshi lang="css"]
.button.small span { font-size: 14px; }
.button.large span { font-size: 28px; }
[/geshi]
With those two lines, we now have two new button sizes. Technically, we don’t need to append the button class to the selector definition but I like to for two reasons: first, it will reduce the chance of another element being affected by the style definition and two, it is more readable for everyone. Let’s make some different colored buttons:
[geshi lang="css"]
.button.red { border-color: #ba6c6c; }
.button.red span {
border-color: #df9f97;
background-color: #d3776c;
background: -webkit-gradient(linear, left top, left bottom, from(#d3776c), to(#b04e2d));
background: -moz-linear-gradient(top, #d3776c, #b04e2d);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=’#d3776c’, endColorstr=’#b04e2d’);
}
.button.red:hover span {
background-color: #d3776c;
background: -webkit-gradient(linear, left top, left bottom, from(#b04e2d), to(#d3776c));
background: -moz-linear-gradient(top, #b04e2d, #d3776c);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=’#b04e2d’, endColorstr=’#d3776c’);
}
.button.red:active span { background: #d3776c; }
.button.blue { border-color: #6caeba; }
.button.blue span {
border-color: #98cde0;
background-color: #6db8d3;
background: -webkit-gradient(linear, left top, left bottom, from(#6db8d3), to(#2d7bb0));
background: -moz-linear-gradient(top, #6db8d3, #2d7bb0);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=’#6db8d3′, endColorstr=’#2d7bb0′);
}
.button.blue:hover span {
background-color: #6db8d3;
background: -webkit-gradient(linear, left top, left bottom, from(#2d7bb0), to(#6db8d3));
background: -moz-linear-gradient(top, #2d7bb0, #6db8d3);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=’#2d7bb0′, endColorstr=’#6db8d3′);
}
.button.blue:active span { background: #6db8d3; }
[/geshi]
We now have class .blue and .red available. We could define any number of colors and sizes this way. After all other styles are defined, we add a ‘disabled’ class which is basically another color class. The reason I put the disabled class at the end is precedence. If the specificity of our colored button class selectors are all the same, the last definition overrides.
[geshi lang="css"]
.button.disabled {
border-color: #c9c9c9;
cursor: default;
}
.button.disabled span,
.button.disabled:hover span,
.button.disabled:active span {
border-color: #dddddd;
background-color: #cfcfcf;
background: -webkit-gradient(linear, left top, left bottom, from(#cfcfcf), to(#b6b6b6));
background: -moz-linear-gradient(top, #cfcfcf, #b6b6b6);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=’#cfcfcf’, endColorstr=’#b6b6b6′);
}
[/geshi]
Finally, let’s put our button in a nice little module that we can imagine lives in a right column somewhere.
[geshi lang="css"]
< div class="box" >
< h1 > Thank you! < /h1 >
< a href="#" class="button" >< span > Youre Welcome! < /span >< /a >
< /div >
[/geshi]
[geshi lang="css"]
.box {
width: 245px;
padding: 15px;
border: 1px solid #ccc;
background-color: #edffff;
text-align: center;
}
.box h1 {
padding-bottom: 10px;
font: bold 20px ‘Helvetica’, sans-serif;
color: #555;
}
[/geshi]
Beautiful. We now have a functional, customizable, button that can be created by simply adding a small amount of HTML.
The key is the development pattern of working from the inside out. By starting first with the button structure and static design, we have control of a generic view of our element, a button unobstructed by any other elements on a page or inherited classes from other stylesheets. We can test the button in different browsers and make sure it looks perfect.
We then define our pseudo classes and inherit styles to make the button respond normally to mouse control and to be able to add other classes to our HTML. Since our button is structured and designed from the inside-out, properties that we care to change are easily manipulated and our selectors remain clean and readable with manageable specificity. This allows for rapid development of new buttons.
Finally, we work our way even further out from the button by bringing it into the page structure. In this example, we simply dropped our button into a box module but we could have easily dropped it at the end of a paragraph, added it to the end of a form, or put it in a lightbox. This separation between elements offers us a few wonderful advantages: first, when we add our button to the page, if the button style changes, we know that there are general CSS classes colliding with our button somewhere else in our application. Second, if we need any unique properties for our button, we can target our button through a parent class and only effect this particular instance of .button.
This modular approach to HTML and CSS design maximizes the re-usability of code, the cleanliness of your work, and will make code much easier for future developers to understand.